我正在创建一个bash脚本,并且在里面的某个地方有以下代码:
if [ $# -eq 2 -a (! -r "$2" -o ! -f "$2") ]; then
echo "rvf: bestand \""$2"\" bestaat niet of is onleesbaar" 1>&2
exit 2
fi
当我尝试在脚本中运行它时,出现此错误:
Syntax Error (bash -n):
rvf: line 14: syntax error in conditional expression
rvf: line 14: syntax error near `-a'
rvf: line 14: `if [[ $# -eq 2 -a (! -r "$2" -o ! -f "$2") ]]; then'
'()'在Bash脚本中如何工作?
答案 0 :(得分:5)
[[
不支持-a
,并且对于[
而言,它被视为已过时且不可移植。使用[
的正确解决方案是
if [ "$#" -eq 2 ] && { [ ! -r "$2" ] || [ ! -f "$2" ]; }; then
使用{ ... }
而不是( ... )
完成分组,以避免创建不必要的子shell。
将[[
简化为
if [[ "$#" -eq 2 && ( ! -r "$2" || ! -f "$2" ) ]]; then
括号可以用于在[[
内部进行分组;作为一种复合命令,与诸如[
(这只是test
的别名,而不是任何语法)之类的普通命令相比,它使用了单独的解析和评估规则。
无论哪种情况,De Morgan's laws都可以使它重构为更简单的方式:
if [ "$#" -eq 2 ] && ! { [ -r "$2" ] && [ -f "$2" ] }; then
if [[ "$#" -eq 2 && ! ( -r "$2" && -f "$2" ) ]]; then
答案 1 :(得分:4)
这里有多个困惑点。
[
可以(作为标准的可选XSI扩展)支持(
作为单独的单词(表示周围需要有空格),但是the POSIX sh specification将其标记为“过时”(例如-a
和-o
),并建议不要使用它。。[[
确实支持(
,但同样,它必须始终是一个单独的单词。但是根本不这样做。如果您将每个测试都保留为自己的简单命令,并且仅将它们与外壳程序的布尔逻辑支持结合使用,那么您将仅使用功能强大且可移植的功能。
也就是说:
if [ "$#" -eq 2 ] && { [ ! -r "$2" ] || [ ! -f "$2" ]; }; then
echo "rvf: bestand \"$2\" bestaat niet of is onleesbaar" >&2
exit 2
fi
答案 2 :(得分:0)
重组您的逻辑。
“不是A还是不是B”只是说“不是(A和B)”的一种更为复杂的方式。
在bash
中,尝试
if [[ "$#" == 2 ]] && ! [[ -r "$2" && -f "$2" ]]; then
更好
if [[ "$#" == 2 && -r "$2" && -f "$2" ]]
then : all good code
else : nope code
fi
更好,
if [[ "$#" == 2 ]] # correct args
then if [[ -r "$2" ]] # is readable
then if [[ if -f "$2" ]] # is a file
then echo "all good"
: do all good stuff
else echo "'$2' not a file"
: do not a file stuff
fi
else echo "'$2' not readable"
: do not readable stuff
fi
else echo "Invalid number of args"
: do wrong args stuff
fi
清除错误日志记录值得一试。
甚至更好,恕我直言-
if [[ "$#" != 2 ]]
then : wrong args stuff
fi
if [[ ! -r "$2" ]]
then : unreadable stuff
fi
if [[ ! -f "$2" ]]
then : do not a file stuff
fi
: do all good stuff