愚かに、私はスクリプトの一部としてこのような条件を使用していました:
if [ $(ls FOO* 2> /dev/null) ] # if files named "FOO*" were downloaded
then
echo "Files found"
# ... process and email results
else
echo "Not found"
# ... email warning that no files were found (against expectations)
fi
これはゼロと1つのファイルという名前のFOO*
で機能しますが、-複数ある場合は失敗しますログから、これに起因するいくつかの異なるエラーメッセージが見つかりました。
[: FOO_20131107_082920: unary operator expected
[: FOO_20131108_070203: binary operator expected
[: too many arguments
私の質問は:Bash if
条件で、名前が1つ以上のファイルで始まるかどうかを確認する正しい方法は何ですかFOO
は存在しますか?
GNU bash、バージョン4.2.25(1)-release(x86_64-pc-linux-gnu)
これは、lsのコマンド置換が空白を出力し、最終的に[
に渡される前にWord分割されるためです。壊れにくい方法は、ファイルを配列に入れ、配列に少なくとも1つのメンバーがあることを確認することです。
shopt -s nullglob
files=( FOO* )
if (( ${#files[@]} )); then
# there were files
fi
これが機能するのは、値が0でない場合にデフォルトで((
がtrueを返し、${#files[@]}
が配列内のアイテム数を取得するためです(グロブに一致するファイルがある場合は、> 0になります)。
nullglob
が設定されていない限り、次のようなこともできます。
if ls FOO* >/dev/null 2>&1; then
# there were files
fi
これはls
の終了コードをチェックするだけです。存在しないファイル名を渡した場合は1になります(リテラルFOO*
、何も一致しない場合(もちろん、あなたが悪でなければ) FOO*
という名前のファイルがあり、その場合は0が返されます:-)))。
これらはどちらもディレクトリと一致することに注意してください。通常のファイルのみを照合する場合は、それをテストする必要があります。
for file in FOO*; do
if [[ -f $file ]]; then
# file found, do some stuff and break
break
fi
done
上記の複数行の回答は、1行のソリューションに対する私の欲求に適合せず、環境を変更しませんでした。これはあなたのために働くかもしれない一般的なワンライナーです:
echo $(ls FOO* 2>/dev/null | wc -w)
/ dev/nullは、ファイルがない場合にls
がエラーをスローするためです。これは単にlsを無視し、「単語」(実際にはファイル名)の数に基づいて見つかったファイルの数を数えます。単純なifステートメントで使用できます。
if [ 0 -lt $(ls FOO* 2>/dev/null | wc -w) ]; then
echo "Some FOO is there."
fi
このアプローチには、一致するファイルが存在するかどうかをチェックするだけでなく、オプションでいくつ一致するファイルが存在するかをチェックするという柔軟性があります(0
および/または-lt
)そして、その上でさらに先へ進みます。
ワイルドカードまたはスペースが含まれているファイル/フォルダーに対してはチェックしていません。上記の方法では、特にスペースで誤ったカウントが発生するのではないかと思います。これは、0を超える正確なカウントが必要な場合にのみ問題となります。これを試みた1つの修正は、$(ls -l FOO* 2>/dev/null | wc -l)
を使用することです。ホワイトスペースをもっと受け入れる。
caseを使用する別のオプションがあります。
FILES=FOO*
FILES=$(echo $FILES)
case $FILES in FOO\*) echo "Not found" ;; esac
これは、テストする引数が1つだけであることを想定しているため機能します。