我发现这种执行if
命令的方法:
$if echo test | grep st ; then echo yes ; fi ; echo $?
test
yes
0
看起来不错。让我们尝试一下不匹配:
$if echo test | grep 123 ; then echo yes ; fi ; echo $?
0
那是不对的。该if
语句运行正常,但返回零退出代码。
有人能为我解释一下吗?
答案1
$?
afterif
块包含语句的退出状态if
。标准指定
命令的退出状态应为或
if
的退出状态then
else
复合列表已执行,如果没有执行则为零。
在第一种情况下,您会看到命令的退出状态echo yes
。第二种情况,then
orelse
块中没有执行任何命令,因此退出状态为0。
答案2
来自 bash 手册(添加了格式和强调):
如果列出;然后列出; [ elif 列表;然后列出; ] ... [ 其他列表; ] 菲
if 列表被执行。如果其退出状态为零,则执行 then 列表。否则,依次执行每个 elif 列表,如果其退出状态为零,则执行相应的 then 列表并完成命令。否则,将执行 else 列表(如果存在)。退出状态是最后执行的命令的退出状态,如果没有条件测试为真,则为零。
所以重要的是要了解退出状态什么你实际上在看。在您的示例中,echo test | grep 123
最后一个命令未成功退出。如果您grep
先执行此操作,然后测试退出状态,您会看到它返回非零退出状态:
$ grep 'noexist' /etc/passwd
$ echo $?
1
相比之下,在 if 语句中,作为条件的命令未测试为 true,因此根据规范和手册 - 退出状态为 0。
顺便说一句,请这样做grep '123'
,因为如果当前目录中有文件 123,则未加引号的模式可能会带来其他问题。
关于 grep 和引用模式的旁注
斯蒂芬·基特在评论对最后一段的阐述。这与本问题的主题不一定相关,并且已经涉及到这一点这里,我回答了类似的问题这里,但我会继续切线,因为这很有趣。让我们看两个例子。
在这里,我们有grep input
一个简单的不带引号的字符串。grep
的语法是将第一个字符串视为模式。这里没问题,这有效:
bash-4.3$ strace -e trace=execve grep input <<< "this is input line"
execve("/bin/grep", ["grep", "input"], [/* 80 vars */]) = 0
this is input line
+++ exited with 0 +++
然而,看看当你有(你认为的)正则表达式时会发生什么。
bash-4.3$ strace -e trace=execve grep input* <<< "this is input line"
execve("/bin/grep", ["grep", "input.txt", "input.txt.bak"], [/* 80 vars */]) = 0
+++ exited with 1 +++
shell 看到了您*
并执行了路径名扩展。现在 shell 运行的实际命令是grep some_file_1 some_file_2 some_file_3
,并且根据grep
语法 - - 该命令现在将在内部grep [OPTIONS] PATTERN [FILE...]
查找字符串。事实上,看看这个:input.txt
input.txt.bak
bash-4.3$ echo "I have input.txt here" > input.txt.bak
bash-4.3$ grep input* <<< "this is input line"
I have input.txt here
输入字符串被完全忽略,grep
仅搜索扩展的文件名,并且您得到了不想要的结果。