我想在 shell if 语句中组合多个条件,并否定该组合。我有以下用于简单条件组合的工作代码:
if [ -f file1 ] && [ -f file2 ] && [ -f file3 ] ; then
# do stuff with the files
fi
这很好用。如果我想否定它,我可以使用以下工作代码:
if ! ( [ -f file1 ] && [ -f file2 ] && [ -f file3 ] ) ; then
echo "Error: You done goofed."
exit 1
fi
# do stuff with the files
这也按预期工作。然而,我发现我不知道括号实际上在做什么。我想仅将它们用于分组,但它实际上会生成子shell吗? (我怎么知道?)如果是这样,有没有办法在不生成子 shell 的情况下对条件进行分组?
答案1
您需要使用{ list;}
而不是(list)
:
if ! { [ -f file1 ] && [ -f file2 ] && [ -f file3 ]; }; then
: do something
fi
他们俩都是分组命令,但{ list;}
在当前 shell 环境中执行命令。
请注意,需要;
in{ list;}
来分隔列表和}
反向单词,您也可以使用其他分隔符。后面的空格(或其他分隔符){
也是必需的。
答案2
到便携式的在 shell 中否定复杂条件,您必须应用德摩根定律并将否定一直推到[
调用中......
if [ ! -f file1 ] || [ ! -f file2 ] || [ ! -f file3 ]
then
# do stuff
fi
...或者你必须使用then :; else
...
if [ -f file1 ] && [ -f file2 ] && [ -f file3 ]
then :
else
# do stuff
fi
if ! command
不是可移植的,也不是[[
。
如果您不需要完全的便携性,不要写 shell 脚本。你其实是更多的/usr/bin/perl
很可能会在随机选择的 Unix 上找到比你还多的人bash
。
答案3
您可以完全使用此test
功能来实现您想要的功能。从手册页test
:
! expression True if expression is false.
expression1 -a expression2
True if both expression1 and expression2 are true.
expression1 -o expression2
True if either expression1 or expression2 are true.
(expression) True if expression is true.
所以你的情况可能是这样的:
if [ -f file1 -a -f file2 -a -f file3 ] ; then
# do stuff with the files
fi
对于否定,请使用转义括号:
if [ ! \( -f file1 -a -f file2 -a -f file3 \) ] ; then
echo "Error: You done goofed."
exit 1
fi
# do stuff with the files
答案4
这不是对您主要问题的完整答案,但我注意到您在评论中提到了复合测试(可读文件);例如,
if [ -f file1 ] && [ -r file1 ] && [ -f file2 ] && [ -r file2 ] && [ -f file3 ] && [ -r file3 ]
您可以通过定义 shell 函数来稍微巩固这一点;例如,
readable_file()
{
[ -f "$1" ] && [ -r "$1" ]
}
将错误处理添加到(例如,[ $# = 1 ]
)以适应口味。上面的第一条if
语句现在可以压缩为
if readable_file file1 && readable_file file2 && readable_file file3
您可以通过缩短函数名称来进一步缩短它。同样,您可以定义not_readable_file()
(或nrf
简称)并在函数中包含否定。