いくつかの条件に応じて、0または1を返す単純な関数をシェルに書きました。関数名をfooとします。
foo(){
...
...
}
ここで、以下のようにif条件でfooを呼び出そうとします。
if ( foo $1 )
...
..
うまくいきます。ただし、次の方法を使用して呼び出すとエラーが発生します。
if [ foo $1 ]
...
...
「単項演算子の予測」エラーが発生するのはなぜですか?
答え1
あなたが使用するとき:
if ( foo $1 )
サブシェルfoo $1
で実行し、if
終了状態に応じて動作します。
あなたが使用するとき:
if [ foo $1 ]
シェルを使用しようとしていますtest
。金持ち有効なテスト演算子ではありません。有効なテスト演算子を見つけることができますここ。
あなたの質問と必ずしも関連があるわけではありませんが、特にシェルテスト角かっこ内で常に変数を引用する必要があります。何かが存在する限り、シェルテストは成功します。したがって、有効なテスト演算子を使用しても不要な結果が生じる可能性があります。
$ unset var
$ [ -n $var ] && echo yes
yes
$ [ -n "$var" ] && echo yes
$ [ -n "" ] && echo yes
$ [ -n ] && echo yes
yes
$ [ foo ] && echo yes
yes
$ [ foo bar ] && echo yes
-bash: [: foo: unary operator expected
シェルテストでは、単一の文字列の存在は、2つ以上の文字列が存在し、文字列の1つが有効なテスト演算子である場合はtrueと評価されます。
答え2
if
ステートメントはコマンドの終了状態を処理します。関数はreturn
状態で終了するか、文字列をエコーする必要があります。あなたの目的にはreturn
より適切に見えます。関数が正常に完了した場合は0を返し、エラーが発生した場合は別の値を返します。例:
$ foo(){ [ -e '/etc/passwd' ] && return 0; }
$ if foo; then echo "/etc/passwd exists"; fi
/etc/passwd exists
実際には、同じコマンドであり、エラーが発生したかどうかを示すためにゼロまたはゼロ以外の終了状態を返すので、 とはまったく同じことがよく見られることif [ ... ]; then...
に注意してください。if test ...; then...
[
test
答え3
他のユーザーが言ったことに加えて、if
複合コマンドの実際の構文は次のとおりです。
if compound_list
then compound_list
[elif compound_list
then compound_list]...
[else compound_list]
fi
デフォルトでは、はcompound_list
複数のコマンドのリストです。if
最初のコマンドの後に続く最後のコマンドの終了コードを調べて、COMPOUND_LIST
実行する項目(、、またはいずれかthen ...
)を決定します。elif ...; then ...
else ...
つまり、次のように書き換えることができます。
if foo "$1"; then
# Code to execute if foo returns 0
else
# Code to execute if foo returns 1
fi
以下を使用することをお勧めしfoo
ます。2
3
254
255
case
foo "$1"
case "$?" in
0) # Code to execute if foo returns 0 ;;
1) # Code to execute if foo returns 1 ;;
2) # Code to execute if foo returns 2 ;;
3) # Code to execute if foo returns 3 ;;
...
254) # Code to execute if foo returns 254 ;;
255) # Code to execute if foo returns 255 ;;
esac
編集1
構文で「$1」を定義した後に「;」はありますか?
はい、Kusalalanandaが言ったように、コマンドの区切り文字として使用されます。
POSIXの定義次のコマンド:
- 簡単なコマンド:
[assignments] program [arguments] [redirections]
- 管路:
[!] command [pipe_operator command]...
- リスト:
- ANDまたはリスト:
pipeline [and-or_list_operator pipeline]...
- 化合物リスト:
and-or_list [compound_list_operator and-or_list]
- ANDまたはリスト:
- 複合コマンド:
- グループ化コマンド:
( compound_list )
{ compound_list; }
- のための:
for name [in words]; do compound_list; done
- ケース:
case word in [[(] patterns ) compound_list ;;]... esac
- 場合:
if compound_list; then compound_list; [elif compound_list; then compound_list;]... [else compound_list;] fi
- しかし:
while compound_list; do compound_list; done
- まで:
until compound_list; do compound_list; done
- グループ化コマンド:
- 機能定義コマンド:
name() compound_command [redirections]
Aはcompound_list_operator
セミコロンまたは改行文字であり、//compound_list
コンテキストfor
で使用されます。case
if
while
until
{ compound_list; }
コマンドの最後のコマンドが閉じ括弧compound_list
と同じ行にある場合でも、}
セミコロンが必要です。