[英]shell scripting process substitution <() inside command substitution $()
我有一个 output 为 1 的命令,类似于:
cmp -bl <(cmp -bl <(echo ABCDEF) <(echo ABDCEF)| wc -l) <(echo 0) |wc -l
我需要将命令 output 与 if 语句中的值进行比较:
if [ $(cmp -bl <(echo ABCDEF) <(echo ABDCEF)| wc -l) = "1" ]; then ...
我遇到的错误与语法有关:意外标记附近的语法错误('
在[
和之前]
之后留一个空格。 [
是一个类似于test
的实际命令。 您需要将命令与其参数分开。 ]
不是命令,但[
命令参数的语法规则也要求将其分开。
if [ $(cmp -bl <(cmp -bl <(echo ABCDEF) <(echo ABDCEF)| wc -l) <(echo 0) |wc -l) = "1" ]; then ...
编辑:使用新版本的问题,加上您所做的评论,答案很简单。 您的代码(您问题的当前版本中的代码)完全可以。 它在我所有使用 bash 的计算机上都能正常工作。 但它是bash。 不是嘘。
如果您将它与 /bin/sh 一起使用(正如您在其中一条评论中所说的那样),那么您得到的错误是
/bin/sh: 1: Syntax error: "(" unexpected
这里出乎意料的括号是<(...)
语法之一。 这是 bash 特定语法。 /bin/sh 不能使用 pip/进程替换。
了解 <(command) 语法是一种特殊的替换。 它在另一个进程中运行命令,output 重定向到 pipe,其文件名被替换为 <(command) 部分。 echo <(ls)
例如显示类似/dev/fd/63
的内容,它是一个名为 pipe 的“文件”,其“内容”是ls
的结果(即使它不是文件,也没有内容.但是读/dev/fd/63就是读ls的output。还是蛮有用的,即使大多数时候,你也不需要它。但它是最近的(好吧,也许一两年。但是当我学习 sh/bash 时它不存在),而不是 /bin/sh 的一部分。
所以答案是:你需要 bash。 你不能在 /bin/sh 中这样做
如果您想将 cmp 与两个命令的 output 一起使用,并且您真的不能只使用#!/bin/bash
而不是#!/bin/sh
,更简单(但效率较低)的解决方案是使用临时文件首先存储命令的结果(希望这些命令不会产生千兆字节的输出),然后比较它们。
或者,您可以使用命名管道重现非常相似的行为。
#!/bin/sh
mknod /tmp/pipe1.$$ p
mknod /tmp/pipe2.$$ p
echo ABCDEF > /tmp/pipe1.$$ &
echo ABCxEF > /tmp/pite2.$$ &
if [ $(cmp -bl /tmp/pipe1.$$ /tmp/pite2.$$ | wc -l) = "1" ]; then
echo One and only one diff
fi
rm /tmp/pipe1.$$
rm /tmp/pipe2.$$
它的作用大致相同 The echo stuff > /tmp/pipe1.$$ &
用于echo stuff
进程(将 echo 替换为您想要的任何命令)。 Whouse output 被重定向到名为 pipe /tmp/pipe1.$$ 我们在第一行创建的。 (.$$ 后缀,只是为了确保没有其他进程可以使用相同的 /tmp/pipe1 名称,因为 $$ 是我们进程的 pid)然后你有一个非常经典的if [ $(cmp /tmp/pipe1.$$ /tmp/pipe2.$$ | wc -l) ]
其中, cmp 只是用两个文件名调用,它们恰好是命名管道(毕竟与 <(...) 完全相同)
但同样,只有当您有充分的理由想要一个纯 sh(而不是 bash)解决方案时。 在这种情况下,您还应该编辑您的问题以删除“bash”标签。
================= 旧答案 ==========================
这对我来说似乎很令人费解。 例如,使用 cmp foo <(echo 0) 将 foo 的内容(foo 本身是 cmp 上的 wc -l 的结果)与 0 进行比较。但我想你已经明白了,你明白这是一个 Rube-Goldberg 装置而不是“== 0”,并且您了解每个 <() 派生一个进程,并从该进程返回一个管道名称(当您需要传递包含执行命令的结果)。
如果不是,你应该解释你真正想要做什么,因为,即使用真正的命令替换 <(echo...) (我也推测这些只是例子),cmp 和 wc 的这几个阶段是不可能的是正确的方法。
话虽这么说,只需在 [ 和 ] 周围添加一个空格,它就会完全按照您的意图进行。 (编辑:正如其他人在更快的回复和评论中所说的那样。我输入的答案太长......我不会删除这个答案,因为序言可能是相关的)
编辑:回复更多关于使用部分
==
仅在 linux 中有效,因为 wc output 是一串数字,仅此而已。 由于标题空格,它不在mac上。 所以1
与1
不同。[
而不是[[
, [
是和外部命令,而[[
是 bash 语法( [[
更好:没有进程的分叉),在将参数传递给[
命令的过程中,空格1
会丢失所以,总的来说
if [[ $(cmp -bl <(echo string1) <(echo string2) | wc -l) -eq 1 ]]
then
echo one and only one difference
fi
应该管用。 同样,不确定它是最快的,也不是最短的,也不是最优雅的解决方案。 但只要没有人提供更好的...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.