为什么我得到"一元运算符预期"错误?

Luk*_*uke 24 bash shell

我正在编写一个shell脚本来简化我的开发工作流程.

它需要一个参数来确定我将要在哪个主题文件夹中工作并从grunt watch该目录开始.

如果我在没有必要参数的情况下调用脚本,我当前正在打印一个警告,指出需要将主题指定为命令行参数.

我想打印一个可用选项列表,例如主题目录

这就是我到目前为止......

THEME=$1

if [ $THEME == '' ]
then
    echo 'Need to specify theme'
else
    cd 'workspace/aws/ghost/'$THEME'/'
    grunt watch
fi
Run Code Online (Sandbox Code Playgroud)

理想情况下,我会用主题父目录替换该echo行的输出,ls如此

THEME=$1

if [ $THEME == '' ]
then
    echo 'Need to specify theme from the following'
    ls workspace/aws/ghost
else
    cd 'workspace/aws/ghost/'$THEME'/'
    grunt watch
fi
Run Code Online (Sandbox Code Playgroud)

但是,这给了我以下错误

./ghost_dev.sh: line 3: [: ==: unary operator expected
Run Code Online (Sandbox Code Playgroud)

Mar*_*eed 51

你需要$THEME这里的报价:

if [ $THEME == '' ]
Run Code Online (Sandbox Code Playgroud)

否则,当您未指定主题时,$THEME展开为空,并且shell会看到此语法错误:

if [ == '' ]
Run Code Online (Sandbox Code Playgroud)

添加引号,如下所示:

if [ "$THEME" == '' ]
Run Code Online (Sandbox Code Playgroud)

而空的扩展$THEME产生了这种有效的比较:

if [ "" == '' ]
Run Code Online (Sandbox Code Playgroud)

运行时语法错误的容量对于那些背景在更传统的编程语言中的人来说可能是令人惊讶的,但是命令shell(至少是Bourne传统中的那些)解析代码的方式有些不同.在许多情况下,shell参数的行为更像宏而不是变量; 这种行为提供了灵活性,但也为不谨慎的人创造了陷阱.

既然你标记这个问题庆典,这是值得注意的是,有关于在bash(和ksh/zsh中)提供的"新"测试语法内部参数扩展的结果,进行无字拆分,即[[... ]].所以你也可以这样做:

if [[ $THEME == '' ]]
Run Code Online (Sandbox Code Playgroud)

这里列出您可以不带引号的地方.但总是引用参数扩展是一个很好的习惯,除非你明确要求分词(即便如此,看看数组是否会解决你的问题).

使用-z测试运算符而不是与空字符串相等将更加惯用:

if [ -z "$THEME" ]
Run Code Online (Sandbox Code Playgroud)

从技术上讲,在这种简单的情况下你不需要引号; [ -z ]评估为真.但是如果你有一个更复杂的表达式,解析器会变得混乱,所以最好总是使用引号.当然,[[...... ]]这里也不需要引号:

if [[ -z $THEME ]]
Run Code Online (Sandbox Code Playgroud)

但是[[...... ]]不是POSIX标准的一部分; 就此而言,两者都不是==.因此,如果您关心与其他POSIX shell的严格兼容性,请坚持使用引用解决方案并使用其中一个-z或一个=.

  • 作业的工作方式略有不同; 至少在RHS上没有发生分词,所以我认为`THEME ="$ 1"`和`THEME = $ 1`是相同的,尽管我很乐意纠正我忘记的角落情况. (3认同)