我对此毫无进展。
我只是想制作一个循环 10 次的 bash 脚本,如果输出包含字符串“连接成功”则中断。
ret=$?
我尝试了类似then 的操作if [$ret -ne 0]
,但我不断地发生 else 语句,即使ret
是 1。
所以现在我尝试使用 grep 搜索“连接成功”一词,但我不知道如何使用该语法。
所以我想要这样的东西:
for i in {1..10}
do
ret=bluetoothctl connect 26:EE:F1:58:92:AF | grep "connection successful"
if [$ret -ne ""]; then
break
fi
done
但显然使用正确的语法$ret=bluetoothctl connect 26:EE:F1:58:92:AF | grep "connection successful"
任何帮助将不胜感激。
答案1
grep
当您只想测试某些文本是否与模式匹配时,很少需要存储输出。相反,只需grep
使用其-q
选项进行调用并对其退出状态进行操作:
#!/bin/sh
tries=10
while [ "$tries" -gt 0 ]; do
if bluetoothctl connect '26:EE:F1:58:92:AF' | grep -q 'connection successful'
then
break
fi
tries=$(( tries - 1 ))
done
if [ "$tries" -eq 0 ]; then
echo 'failed to connect' >&2
exit 1
fi
如果bluetoothctl
在失败和成功时返回正常的退出状态,那么您甚至不需要grep
并且可以将if
循环中的 - 语句缩短为以下内容:
if bluetoothctl connect '26:EE:F1:58:92:AF' >/dev/null
then
break
fi
事实上,您也可以将bluetoothctl
循环条件作为一部分(假设您从for
循环切换到使用while
循环,就像我在这里展示的那样):
#!/bin/sh
tries=10
while [ "$tries" -gt 0 ] && ! bluetoothctl connect '26:EE:F1:58:92:AF'
do
tries=$(( tries - 1 ))
done >/dev/null
if [ "$tries" -eq 0 ]; then
echo 'failed to connect' >&2
exit 1
fi
考虑使用https://www.shellcheck.net验证 shell 脚本的语法。对于问题中的脚本,它会指出测试需要以下空格[ ... ]
:
if [$ret -ne ""]; then
^-- SC1009 (info): The mentioned syntax error was in this if expression.
^-- SC1035 (error): You need a space after the [ and before the ].
^-- SC1073 (error): Couldn't parse this test expression. Fix to allow more checks.
^-- SC1020 (error): You need a space before the ].
^-- SC1072 (error): Missing space before ]. Fix any mentioned problems and try again.
测试非空字符串是用[ -n "$ret" ]
or完成的[ "$ret" != "" ]
。请注意,这-ne
是一个算术测试。
您也没有将管道的输出正确分配给ret
.不幸的是,语法绝对正确,但执行的操作完全不同,因此 ShellCheck 不会识别它。你打算使用的是
ret=$( bluetoothctl ... | grep ... )
答案2
Kusalananda 给出了如何改进代码的提示,但没有准确解释你做错了什么。让我们回顾一下:
ret=$?
我尝试了类似then 的操作if [$ret -ne 0]
,但即使 ret 为 1,我仍然会发生 else 语句。
[
是一个命令,因此您需要在命令及其参数之间放置一个空格,否则参数将被理解为命令名称的一部分。如果ret
设置为1
,bash 应该输出错误[1: command not found
,并且if
应该因为错误而看到 falsy 。同样,[
要求最后一个参数为]
,0]
不是这样。您还需要在那里有一个空间。
你想要的是:
if [ "$ret" -ne 0 ]
下一部分:
ret=bluetoothctl connect 26:EE:F1:58:92:AF | grep "connection successful"
您在这里所做的是运行 pipeline connect 26:EE:F1:58:92:AF | grep "connection successful"
,同时为connect
命令(可能不存在)提供ret
值为 value 的环境变量bluetoothctl
。
为了收集其输出,您需要将命令括在$()
:
ret="$(bluetoothctl connect 26:EE:F1:58:92:AF | grep "connection successful")"
对这个:
if [$ret -ne ""]; then
你也有同样的缺少空格的问题,但需要进一步理解的是,基本上大多数东西都是 bash 中隐式的字符串,引号主要只是一种更明确的方式(除了控制扩展的一些细节之外)。这意味着它的[$ret -ne ""]
计算结果与以下内容几乎完全相同:
[$ret -ne ]
[$ret -ne ""''""'']
"["$ret "-ne" """]"
"["$ret"" "-ne""""" """]"""
如果$ret
为空,则等同于[ -ne ]
。它的计算结果为 true,因为只有一个参数(忽略]
),[
检查它是否是一个非空字符串,并且-ne
是。
如果$ret
是其他类似的东西foo bar baz
,它会因为缺少引号而被分词,并且你会得到命令[foo bar baz -ne ]
,它有 4 个参数(包括]
)并且是假的,因为 bash 找不到命令[foo
。如果你引用了$ret
like ["$ret" -ne ""]
,那么你会得到等价的"[foo bar baz" -ne ]
,它将有 2 个参数(包括]
)并且也是假的,因为 bash 找不到该命令[foo bar baz
。
您在这里犯的另一个错误是使用-ne
,它专门用于数字比较。即使您解决了空格和引号问题,bash 也会给您错误integer expression expected
。您想要的是!=
,用于字符串比较。
总结并解决所有这些问题,您想要的是:
if [ "$ret" != "" ]; then
也可以写成
if [ -n "$ret" ]; then
或者
if [ "$ret" ]; then