为什么在'if'语句中必须在下一行?

时间:2019-09-07 13:30:23

标签: bash if-statement

if之后是bash中的then,但我不明白为什么then不能像if [...] then一样用于同一行,下一行。这样可以消除代码中的歧义吗?或bash是这样设计的?其根本原因是什么?

我尝试在同一行中编写ifthen,但出现以下错误:

./test: line 6: syntax error near unexpected token \`fi'
./test: line 6: \`fi'

代码是:

#!/bin/bash
if [ $1 -gt 0 ] then
echo "$1 is positive" 
fi

4 个答案:

答案 0 :(得分:5)

必须在前面加上一些描述的分隔符,而不是在下一行(a)上。换句话说,要实现您想要的,只需使用:

if [[ $1 -gt 0 ]] ; then
    echo "$1 is positive"
fi

顺便说一句,对于像这样的单线客,我倾向于:

[[ $1 -gt 0 ]] && echo "$1 is positive"

但这只是因为我更喜欢在屏幕上看到尽可能多的代码。这实际上只是一种样式,您可以随意忽略。


(a)的原因可以在Bash联机帮助页(我的重点)中找到:

  

保留字:保留字是对shell具有特殊含义的字。以下单词在不加引号的情况下被识别为保留,并且是 简单命令的第一个单词 (请参见下面的SHELL GRAMMAR)或case的第三个单词,或者for命令:

     

! case coproc do done elif else esac fi for function if in select then until while { } time [[ ]]

请注意,尽管该部分指出它是“简单命令的第一个单词”,但联机帮助页似乎在所引用的SHELL GRAMMAR部分中与自己矛盾:

  

一个简单的命令是一系列可选的变量分配,后跟用空格分隔的单词和重定向,并由控制操作符终止。 第一个单词指定要执行的命令 ,并作为参数零传递。

因此,是否将其视为下一个命令的一部分或某种分隔符是有争议的。 不是可以争论的是,它在then关键字之前需要某种分隔符(例如,换行符或分号)。

该手册页没有涉及到为什么这样设计的问题,但是可能可以使命令的解析更加简单。

答案 1 :(得分:2)

也许通过一些例子来了解为什么会这样。 if的参数是命令的序列;所以你可以说

if read -r -p "What is your name?" name
    [ "$name" -eq "tripleee" ]
then
    echo "I kneel before thee"
fi

或什至是复杂的化合物

while read -r -p "Favorite number?" number
    case $number in
        42) true; break;;
        *) false;;
    esac
do
    echo "Review your preferences, then try again"
 done

shell的这一极其强大但可能令人困惑的功能可能是它最容易被误解的构造之一。将命令序列传递到流控制语句的功能可以使脚本变得非常优雅,但通常会被完全忽略(例如,参见Why is testing "$?" to see if a command succeeded or not, an anti-pattern?

答案 2 :(得分:2)

这是解释then之前是否需要换行或分号的另一种方法:ifthen之间的是命令(或命令序列);如果then刚好在命令后没有分隔符,那么将其视为shell关键字还是仅作为命令的参数将是不确定的。

例如,这是一个完全有效的命令:

echo This prints a phrase ending with then

...将显示“这将打印一个以then结尾的短语”。现在,考虑这一点:

if echo This prints a phrase ending with then

应该打印“这将打印一个以此结尾的短语”并在以后寻找then关键字,还是应该打印“这将打印一个以此结尾的短语”并将then视为关键字?

为了解决这种歧义,shell语法表示应将“ then”作为echo的参数,并且要将其视为关键字,您需要命令定界符(换行符或分号)标记命令的结束。

现在,您可能会认为您的if条件[ $1 -gt 0 ]已经有了一个很好的定界符,即]。但是在shell语法中,这实际上只是[命令的一个参数(是的,这是一个命令)。尝试以下命令:

[ 1 -gt 0 ] then

......您可能会收到类似“ -bash:[:missing']'”的错误,因为[命令检查了其最后一个参数以确保它是“]”,因此发现而是“然后”,并感到恐慌。

答案 3 :(得分:-2)

如果有帮助,可以使用分号

if [ $1 -gt 0 ]; then
echo "$1 is positive" 
fi

# or even

if [ $1 -gt 0 ]; then echo "$1 is positive"; fi

关于为什么,它帮助我将ifthenelsefi视为bash命令,而仅仅是像所有其他命令一样,它们需要位于一行的开头(或分号之后)。