为什么没有[echo $ foo | grep -q吧]工作?

时间:2016-03-31 16:18:57

标签: bash

我尝试读取用户输入并将其与存储值进行比较,如下所示:

read confirm
if [ echo $confirm | grep -q y ]; then
  ...
fi

但是,这会导致一对错误:

[: missing `]'
grep: ]: No such file or directory

为什么会发生这种情况,以及适当的选择是什么?

1 个答案:

答案 0 :(得分:4)

简答

对于您的直接用例,您只需要:

if echo "$confirm" | grep -q y; then

...或其效率更高的等价物(如果你的shell是bash):

if [[ $confirm = *y* ]]; then

...或更有效的等价物(对于任何 POSIX shell):

case $confirm in *y*) echo "Put your code for the yes branch here" ;; esac

为什么原来是错的?

[不是if语法的一部分:if只是在then之前将(可能是复合的)命令作为其参数。 [test命令的不同名称,它对其参数运行检查;但是,如果您要测试的是grep -q退出状态,则根本不需要为此调用test命令。

如果在|命令中放置[,则会使复合命令成为管道,并启动一个新的简单命令。因此|之后的参数不再传递给[

使用原始代码:

if [ echo $confirm | grep -q y ]; then

...这是在运行两个命令,它们之间有一个管道:

[ echo $confirm # first command
grep -q y ]     # second command

由于[要求其最后一个参数为],因此它报告缺少该强制参数;由于grep将额外的参数视为要读取的文件名,因此它抱怨没有找到名为]的文件。

此外,[ "$foo" ]检查foo的内容是否为空。由于grep -q的输出总是为空,[ "$(echo "$confirm" | grep -q y)" ]虽然在语法上正确,但总是会评估为false,即使{{>>退出状态 {{ 1}}更改以指示是否找到匹配项。 (grep -q相反,是一种可以发出正确结果的替代方法 - 使用[ "$(echo "$confirm" | grep y)" ]来测试[ ]的输出是否为空 - 但效率低于最佳实践方法)。

正式grep语法

来自if

  

help if

     

执行if: if COMMANDS; then COMMANDS; [ elif COMMANDS; then COMMANDS; ]... [ else COMMANDS; ] fi列表。如果它的退出状态为零,那么      if COMMANDS列表已执行。否则,每个then COMMANDS列表都是      依次执行,如果其退出状态为零,则对应      执行elif COMMANDS列表,if命令完成。除此以外,      执行then COMMANDS列表(如果存在)。退出状态      整个构造是最后执行的命令的退出状态,或者为零      如果没有条件测试成真。

值得注意的是,else COMMANDS采用了一系列命令,语法规范中不包含if