次のロジックを使用して簡単なスクリプトを作成しようとしています。最初の引数が有効な汎用ファイルの場合はforループを実行し、引数が指定されていない場合は「code2」を実行し、それ以外の場合は「code3」を実行します。以下のスクリプトは私がうまくいくようですが、引数なしで実行すると中断されます。
#!/bin/bash
if [ -f $1 ]; then
for i in `cat $1`
do
<something>
done
elif [ $# -eq 0 ]; then
"code2"
else
"code3"
fi
これはデバッグ出力で、最後に停止しました。
bash -x myscript
+ '[' -f ']'
++ cat
パラメータを提供していませんが、なぜ最初のif-thenフローに到達するのですか?私は初めてbashスクリプトに触れました。どんな助けでも大変感謝します。
答え1
変数を参照しないと、"$1"
何もなく消えます。その後、実行されるコードは次のとおりです(-x
シェルオプションで報告されています)。
[ -f ]
ここでは、-f
長さがゼロ以外の文字列のため、実際のテストはそのセクションを実行しますthen
。
(少なくとも)次のように書く必要があります。
[ -f "$1" ]
空の引数がある場合は、次のようになります。
[ -f "" ]
ファイル一致の失敗を報告します""
。
別の選択肢は、パラメータ拡張を使用することです(外部参照は必要ありません)。
[ -f ${1:-""} ]
""
値が$1
nullまたは空の場合はに展開されます。
そして、ファイル行を繰り返すためにforループを実行しないでください。while read
ループの使用を考慮する必要があります
#!/bin/sh
if [ -f ${1:-""} ]; then
while read -r line; do
echo '<something>'
done <"$1"
elif [ "$#" -eq 0 ]; then
echo "code2"
else
echo "code3"
fi
答え2
簡単な答えは、存在しないものについても$1
引用されていないからです(また問題の一部)。シェルは式を次のように扱い、[ -f ]
ここに表示される-f
のは[
フラグとして認識されず、ただ単一の「表現式」。実際には次のようになります。
$ [ abracadabra ] && echo "success"
success
そしてマニュアルを引用しますtest
(わからない場合はエイリアスです[
)。
An omitted EXPRESSION defaults to false. Otherwise, EXPRESSION is true or false and sets exit
status. It is one of:
( EXPRESSION )
EXPRESSION is true
式を引用すると、出力を追跡するときに次のようになります。つまり、実際には空の文字列を既存のファイル名で評価しようとします。
$ (set -x; [ -f "$this_var_doesnt_exist" ] && echo "hi" )
+ '[' -f '' ']'