问题描述
我有一个非常简单的 bash 脚本,它可以卷曲 URL,计算响应中的子字符串,如果找到该字符串,则运行一些代码。
本来我是这样写的:
RESP=$(curl -s 'https://theurl.com' | grep -ic substring)
if [ $RESP > 0 ];
do something
else
do something else
fi
当我将它设置为作为本地用户启动代理在 launchd 中运行时,if 语句从未评估为真。
我在调试过程中尝试的事情:
最终,我能够通过将 if 更改为:
if [ $RESP -ge 1 ]
这在两个地方都有效,但我不明白为什么完全相同的解释器中完全相同的脚本在两个地方的评估结果不同。
有什么想法吗?
解决方法
这是因为 >
没有做您认为的那样。命令
[ $RESP > 0 ]
被 shell 视为一种有趣的写作方式
[ $RESP ] > 0
也就是说,它运行命令 [
(是的,这是一个实际的命令,本质上等同于 test
),扩展 $RESP
和“]
”为论据。 > 0
位于 [
的参数中间这一事实无关紧要;您可以在命令...参数序列中的任何位置放置一个重定向运算符,它的作用相同。
最终结果:[
检查 $RESP
是否扩展为非空字符串(如果扩展则成功),并将其(空)输出发送到名为“0”的文件。
至少,这是它通常的做法。我怀疑当你将它作为启动代理运行时,它在创建“0”文件时出错,所以它失败了。由于它失败了,而且它是 if
语句的条件,因此 else
子句运行。
要在 >
测试表达式中使用 <
或 [ ]
,您需要引用或转义它,例如 [ "$RESP" ">" 0 ]
或 [ "$RESP" \> 0 ]
。此外,>
无论如何都是错误的测试运算符;如果您要比较整数,请改用 -gt
。在 [ ]
测试表达式中,>
表示排序顺序比较(因此 [ 9 ">" 10 ]
为真,因为“9”排在“1”之后)。
这看起来很奇怪,但正如 Cyrus 在评论中指出的那样,命令 [ $RESP > 0 ]
创建了一个名为 0
的文件。如果您从 launchd 运行脚本,则此类文件的创建可能会失败,因为工作目录与您在终端中运行脚本时的工作目录不同。由于无法创建文件,if ...
检查失败并进入 else
分支。
现在,为什么这会创建一个文件。 bash -c 'help test'
([
是 test
的同义词)明确说明
STRING1 > STRING2
如果 STRING1 按字典顺序排在 STRING2 之后,则为真。
但是,在 test
/[
看到 >
之前,bash 处理它并将其解释为重定向。下面三个命令实际上是等价的:
echo string > file
echo > file string
> file echo string
因此,您执行测试 [ $RESP ]
并将(空)输出重定向到文件 0
。
要使用 >
中的 test
,您必须引用它,例如:[ $RESP ">" 0 ]
。但是,正如您已经注意到的,您想改用 -gt
。
注意:要检查是否找到任何匹配项,您可以改为切换到 grep -q
:
if curl -s 'https://theurl.com' | grep -iq substring; then
# do something
else
# do something else
fi