予期しないトークン「fi」の近くの構文エラー


17

必ずしも答えが欲しいわけではありませんが、誰かが私にいくつかの文献や例を教えてくれれば。私はそれを把握したいと思います。

スクリプトを実行すると、エラーが表示されます。

予期しないトークンの近くの構文エラー fi

私はif自分のif声明にコメントをつけ、追加することで私の声明に私の問題があることを推測しecho "$NAME"ました/etc/

変更を加えると、#from ifを削除してto にfi追加する#wc -c "$NAME"、上記の構文エラーが表示されます。;その間に追加しました]。またthen、解像度なしで次の行に移動しました。

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

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

9
シェル構文エラーが発生した場合は、まず最初に、コードを切り取ってshellcheck.netに貼り付け、識別されたエラーを修正してください。メッセージを理解できない場合は、ここに来て質問してください。
John1024

2
どうするの-af
イルッカチュ

そのサイト@ John1024が最も便利だったことに感謝します。今後の参考のためにブックマークしました。
クリスティーナAグズマン

1
@ChristinaAGuzmanこのような場合-a、条件はに既に含まれているため冗長-fです。---とにかく[ ](このコマンドはとしても使用可能test)内の複数の条件は、-a(and)または-o(or)などの論理演算子を使用して結合する必要がありますが、以下の応答で提案されているように、複数の[ ]test)コマンドを使用して結合することをお勧めします&&またはのようなシェル演算子を使用します||
パブーク

2
Christinaは@ John1024で指摘したように、shellcheck.netは(lintがCコードで行うように)いくつかの構文またはさらに深い間違いを非常に明確に示しています。また、必読をお勧めします:mywiki.wooledge.org/BashPitfalls(少なくとも1回は読んでください!)およびmywiki.wooledge.org/BashFAQmywiki.wooledge.org/BashGuideも読むのが良いでしょう。
オリビエデュラック

回答:


46

以下のようなキーワードifthenelsefiforcaseおよびシェルがコマンド名を見込ん場所にあることが必要でそう。それ以外の場合は、通常の単語として扱われます。例えば、

echo if

印刷するだけでif、条件付き命令を開始しません。

したがって、行で

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

単語thenはコマンドの引数です[(実行できた場合に文句を言うでしょう)。シェルはを探し続け、コマンド内の位置thenを見つけfiます。ifそのを探しているがまだあるのでthenfiは予期せず、構文エラーがあります。

thenキーワードとして認識されるように、前にコマンドターミネータを配置する必要があります。最も一般的なコマンドターミネータは改行ですが、以前thenはセミコロン(改行とまったく同じ意味)を使用するのが一般的です。

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

または

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

これを修正すると、コマンド[が理解できないため、コマンドから別のエラーが発生します-af。おそらくあなたは

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

テストコマンドはオプションのように見えますが、このようにバンドルすることはできません。それらは[コマンドの演算子であり、それぞれ別々の単語にする必要があります(do [および])。

ちなみに、[ -r "$NAME" -a -f "$NAME" ]動作しますが、私はどちらかを書くことをお勧めします

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

または

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

それは保つのがベストです[ … ]ので、条件付きのシンプルな[コマンドを簡単にオペランドから演算子を区別することはできません。場合は$NAME、オペレータが有効である位置にいるオペレータ、表示されたように見える、それがオペレーターとして解析することができます。これは、この回答で見られる単純なケースでは発生しませんが、より複雑なケースは危険です。[シェルの論理演算子を個別に呼び出して使用してこれを記述すると、この問題を回避できます。

2番目の構文は、[[ … ]]bash(およびkshとzshに存在しますが、shにはありません)に存在する条件構造を使用します。この構築物のに対し、特別な構文で[、他のコマンドと同様に解析され、これあなたがのようなものを使用することができます&&内側にし、あなたには、いくつかの文字列演算子の引数を除いて、変数を引用する必要はありません(===!==~)(参照必要なダブル引用されている場合?


if [[ 1 ]] then [[ 2 ]] fiksh、pdksh、zsh で動作することに注意してください。if(:)then(:)fiすべてのシェルで動作します。
ステファンシャゼラス

12

変更点は次のとおりです

if [-r "$ NAME" -a -f "$ NAME"] ; それから
#^^^^^ ^
     wc -c "$ NAME"
fi

ifブロック内のすべてのコマンドを削除する場合は、少なくとも次のようにコロンを追加する必要があります。

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

または1行バージョン

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


2

他の人はすでに指摘しましたが、公式のリファレンスを探しているならRTM

リストの場合; 次にリスト; [elifリスト; 次にリスト; ] ... [elseリスト;] fi

ifリストが実行されます。終了ステータスがゼロの場合、リストが実行されます。それ以外の場合、各elifリストが順番に実行され、その終了ステータスがゼロの場合、対応するthenlistが実行され、コマンドが完了します。そうでない場合、elseリストが実行されます(存在する場合)。終了ステータスは、最後に実行されたコマンドの終了ステータス、または真とテストされた条件がない場合はゼロです。

あなたが欠けています ;

の構文listman test

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.