意外令牌`fi`附近的语法错误


17

我不一定想要答案,但是如果有人可以指出一些文献或例子。我想弄清楚。

当我运行脚本时,收到错误消息:

意外令牌附近的语法错误 fi

if通过在if语句中添加注释并在echo "$NAME"中显示名称来推断出问题出在我的语句中/etc/

进行更改时,#if和删除fi并添加#wc -c "$NAME",我收到上面列出的语法错误。;在此之间我添加了]。我也then没有解决地移到了下一行。

#!/bin/bash
for NAME in /etc/*
do

     if [ -r "$NAME" -af "$NAME" ] then
          wc -c "$NAME"
     fi
done

9
每当遇到shell语法错误时,一个好的第一步就是将您的代码剪切并粘贴到shellcheck.net中并更正它所标识的错误。如果您在理解其信息时遇到困难,请到这里询问。
John1024 '17

2
-af应该怎么办?
ilkkachu

感谢您对该站点@ John1024的使用,它非常有用,我将其添加为书签,以备将来参考。
克里斯蒂娜·古兹曼

1
@ChristinaAGuzman在这种情况下-a是多余的,因为条件已包含在中-f。---无论如何[ ](该命令也可作为test)中的多个条件必须使用-a(和)或-o(或)之类的逻辑运算符进行联接,但正如下面的答复所建议的那样,最好使用多个[ ]test)命令并联接他们使用shell运算符,例如&&||
pabouk

2
克里斯蒂娜(Christina)如@ John1024所指出,shellcheck.net非常清楚地显示了某些语法甚至更深层次的错误(就像lint对于C代码所做的那样)。我还建议您务必阅读:mywiki.wooledge.org/BashPitfalls(至少阅读一次!)以及mywiki.wooledge.org/BashFAQmywiki.wooledge.org/BashGuide也很容易阅读。
奥利维尔·杜拉克

Answers:


46

关键词一样ifthenelsefiforcase等需要在其中壳预期的命令名称的地方。否则,它们被视为普通单词。例如,

echo if

只是打印if,它不会启动条件指令。

因此,在行中

if [ -r "$NAME" -af "$NAME" ] then

这个词then是命令的参数[(如果要运行,它将抱怨)。Shell继续寻找then,并fi在命令位置找到一个。由于if仍然在寻找它then,这fi是意外的,因此存在语法错误。

您需要在前面放置命令终止符,then以便将其识别为关键字。最常见的命令终止符是换行符,但在此之前then,通常使用分号(其含义与换行符完全相同)。

if [ -r "$NAME" -af "$NAME" ]; then

要么

if [ -r "$NAME" -af "$NAME" ]
then

修复该错误之后,该命令将导致另一个错误,[因为它无法理解-af。你大概是说

if [ -r "$NAME" -a -f "$NAME" ]; then

尽管测试命令看起来像选项,但是您不能像这样捆绑它们。它们是[命令的运算符,并且每个都必须是一个单独的词([和和一样])。

顺便说一下,尽管[ -r "$NAME" -a -f "$NAME" ]可行,但我还是建议写

[ -r "$NAME" ] && [ -f "$NAME" ]

要么

[[ -r $NAME && -f $NAME ]]

最好使[ … ]条件简单,因为该[命令不能轻易将运算符与操作数区分开。如果$NAME看起来像一个运算符并且出现在该运算符有效的位置,则可以将其解析为运算符。在此答案中看到的简单情况下不会发生这种情况,但是更复杂的情况可能会有风险。通过分别调用[和使用Shell的逻辑运算符来编写此代码可以避免此问题。

第二种语法使用[[ … ]]存在于bash(以及ksh和zsh,但不是普通sh)中的条件构造。此结构是特殊的语法,而[被解析像任何其他命令,这样就可以使用之类的东西&&里面,你不需要引用变量除了在参数一些字符串操作符(===!==~)(见当是双引号必要?以获取详细信息)。


请注意,它if [[ 1 ]] then [[ 2 ]] fi可以在ksh,pdksh和zsh中使用。if(:)then(:)fi适用于所有外壳。
斯特凡Chazelas

12

查看更改内容如下

如果[-r“ $ NAME” -a -f “ $ NAME”] ; 然后
#^^^^^ ^
     wc -c“ $ NAME”
科幻

如果要删除if块中的所有命令,则至少需要在其中添加冒号,例如

if [ -r "$NAME" -a -f "$NAME" ]; then
    :
fi

或单行版本

if [ -r "$NAME" -a -f "$NAME" ]; then :; fi


2

其他人已经指出,但是如果您要寻找官方参考,那么RTM

如果列表;然后列出;[elif list; 然后列出;] ... [else list;] fi

如果列表被执行。如果其退出状态为零,则执行then列表。否则,依次执行每个elif列表,如果其退出状态为零,则执行相应的thenlist并完成命令。否则,将执行else列表(如果存在)。退出状态是最后执行的命令的退出状态,如果没有条件测试为真,则为零。

你错过了 ;

的语法listman test

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.