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

Man*_*nik -1 bash if-statement

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

我试着写if,并then在同一行,但它给了以下错误:

./test: line 6: syntax error near unexpected token \`fi'
./test: line 6: \`fi'
Run Code Online (Sandbox Code Playgroud)

代码是:

#!/bin/bash
if [ $1 -gt 0 ] then
echo "$1 is positive" 
fi
Run Code Online (Sandbox Code Playgroud)

Gor*_*son 7

这是解释前面需要换行或分号的另一种方法:和then之间的内容是命令(或命令序列);如果直接出现在命令后面且没有分隔符,那么是否应将其视为 shell 关键字或仅将其视为命令的参数将是不明确的。ifthenthen

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

echo This prints a phrase ending with then
Run Code Online (Sandbox Code Playgroud)

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

if echo This prints a phrase ending with then
Run Code Online (Sandbox Code Playgroud)

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

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

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

[ 1 -gt 0 ] then
Run Code Online (Sandbox Code Playgroud)

...你可能会得到一个类似“-bash: [: Missing ']'”的错误,因为该[命令检查了它的最后一个参数以确保它是“]”,发现它是“then”,并且惊慌失措。


pax*_*blo 5

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

if [[ $1 -gt 0 ]] ; then
    echo "$1 is positive"
fi
Run Code Online (Sandbox Code Playgroud)

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

[[ $1 -gt 0 ]] && echo "$1 is positive"
Run Code Online (Sandbox Code Playgroud)

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


(a)可以在Bash联机帮助页中找到原因(我强调):

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

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

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

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

因此,是否将其视为下一个命令的一部分还是某种分隔符是有争议的。什么是值得商榷的是,它之前需要某种形式的分离器(换行或分号,例如)then关键字。

该手册页没有介绍为何采用这种方式设计,但可能是为了使命令的解析更简单。