我正在尝试使用 Bash 中的 new-test 编写复合 if 语句。我想检查一个文件是否存在,以及另外两个文件是否具有特定内容。当嵌套在测试中时,我的 grep 搜索似乎不太好用。
echo "a" >> file_a
echo "b" >> file_b
echo "c" >> file_c
if [[ -f file_a && \
$(grep -q "b" file_b) && \
$(grep -q "c" file_c) ]]; then
echo "Got 'em"
fi
答案1
当测试命令的退出状态(例如grep
)时,您不需要或不想要[[ ]]
或$( )
或任何这些东西。检查和if
之间的任何退出状态,并根据其成功或失败采取适当的分支。if
then
$( )
存在的目的是为了捕获命令的输出(即运行时打印的内容 -grep -q
不打印任何内容),并将其用作另一个命令的一部分。这根本不是你想要的。
[[ ]]
评估测试表达式(例如,可以测试文件是否存在、两个字符串是否相等等),并将结果转换为退出状态。但由于grep -q
它已经产生了退出状态,因此您不需要进行某种测试来将其转换为该形式。
你做需要[[ ]]
检查 file_a 是否存在,但这是它在这里唯一要扮演的角色。并且您需要&&
创建一个复合命令,只有当它的所有部分都成功时,该命令才会成功。因此,您需要的是:
...
if [[ -f file_a ]] &&
grep -q "b" file_b &&
grep -q "c" file_c; then
...
答案2
您可以从 grep 中删除-q
,并使用该标志测试命令替换内的表达式是否不为空-n
。
if [[ -f file_a && -n $(grep "b" file_b) && -n $(grep "c" file_c) ]]; then
echo "Got 'em"
fi
虽然可以省略,但它会像在测试内部
-n
有标志一样工作。-n
通常, 如果您只是要使用 grep 测试模式匹配,则不需要
if
子句和[[
或。[
答案3
或者,完全去掉“如果”:
test -f file_a && grep -q "b" file_b && grep -q "c" file_c && echo "Got em"
答案4
grep
成功时退出代码为 0,但需要test
真值。您必须反转 grep 的退出代码或检查它是否以 0 退出:
if [[ -f file_a && \
! $(grep -q "b" file_b) && \
! $(grep -q "c" file_c) ]]; then
echo "Got 'em"
fi
或者
if [[ -f file_a && \
$(grep -q "b" file_b) -eq 0 && \
$(grep -q "c" file_c) -eq 0 ]]; then
echo "Got 'em"
fi
理想情况下,有一种比将其放入子 shell 中更易读的方法$()
。