在桀骜
echo 'a string' > test.txt
echo $?
0
和
[[ $(echo 'a string') ]]
echo $?
0
然而
[[ $(echo 'a string' > test.txt) ]]
echo $?
1
另一个例子
curl -so 'curl-8.2.1.tar.gz' https://curl.se/download/curl-8.2.1.tar.gz
echo $?
0
或者
[[ $(curl -so 'curl-8.2.1.tar.gz' https://curl.se/download/curl-8.2.1.tar.gz) ]]
echo $?
1
我的问题:
- 这是因为输出重定向吗?如果不是,是什么原因造成的?
- 命令执行成功:
a string
出现在test.txt
并且curl将文件下载到我指定的输出文件中,为什么评估结果为false
? - 在脚本中是否有一种合理的方法来处理这个问题?假设我想执行某个命令,如果前一个命令执行成功(但
false
仍然返回),应该如何执行?我可以添加第二次检查来查看该行是否出现或文件是否已下载,但首先就不需要评估命令是否成功执行。
更多完整性示例(可读性与“正确性”?):
if ( $(echo 'a string' > text.txt) ); then echo yes; else echo no;fi
yes
if (( $(echo 'a string' > text.txt) )); then echo yes; else echo no;fi
no
if $(echo 'a string' > text.txt); then echo yes; else echo no;fi
yes
if echo 'a string' > text.txt; then echo yes; else echo no;fi
yes
答案1
$?
在里面由外壳设置的参数man 的部分zshparam
,或者info zsh 'Parameters Set By The Shell'
你会看到,$?
是最后一个命令返回的退出状态。
$(...)
在人身上zshexpn
,或者info zsh 'Command Substitution'
你会看到:
命令替换
'$(...)'
括在括号中且前面带有美元符号(如)或用重音符号引用(如)的命令...
将被替换为其标准输出,并删除所有尾随换行符。
例如,表达式$(echo 'a string')
将被替换为该命令 ( ) 的输出,a string<newline>
并删除尾随换行符,从而得到a string
.但里面的命令$(echo 'a string' > test.txt)
不会向标准输出产生任何输出,因此该表达式的结果是一个空字符串。
[[ ... ]]
zshmisc
在或的手册页中info zsh 'Conditional Expressions'
,您将看到:
条件表达式
条件表达式与复合命令一起使用
[[
来测试文件的属性并比较字符串。每个表达式都可以由以下一个或多个一元或二元表达式构造:
[...]
为了兼容性,如果有一个在语法上不重要的参数(通常是变量),则条件被视为 测试表达式是否扩展为非零长度的字符串。
现在举个例子
因此,在下一行中, 中命令的输出$( ... )
是字符串a string<newline>
,因此其自身的扩展$(...)
将是a string
,这是一个非零长度的字符串,因此[[ ... ]]
计算将返回 true(0 退出状态)。
[[ $(echo 'a string') ]]
但在下面的命令中,由于您进行了重定向,因此 的扩展$( ... )
将是零长度字符串,并且[[ ... ]]
计算将返回 false(退出状态 1,是 0 以外的数字)。
[[ $(echo 'a string' > test.txt) ]]
同样,下面命令的退出状态就是该curl
命令的退出状态。
curl -so 'curl-8.2.1.tar.gz' https://curl.se/download/curl-8.2.1.tar.gz
will的联机帮助页curl
说明了在什么条件下它返回非零(失败)退出状态。
但在下一个示例中,退出状态将取决于curl
命令是否有任何输出(成功)或没有任何输出(失败)。
[[ $(curl -so 'curl-8.2.1.tar.gz' https://curl.se/download/curl-8.2.1.tar.gz) ]]
(( ... ))
我就到这里为止,但是你可以继续阅读手册,例如算术评估人的一部分zshmisc
(或info zsh 'Arithmetic Evaluation'
)
答案2
我由此得出结论, using[[ ... ]]
不适合评估成功的命令执行,除非以命令的输出结果产生非零字符串的方式理解成功的命令执行。为了在 zsh 脚本中进行验证,正确的方法是
if command; then ...; [else ...;] fi
(按照 muru 的评论所述使用)- 单独运行该命令并
$?
随后检查其退出代码,和/或 - 验证命令的实际输出,例如通过检查它生成的文件的内容