コマンドが空の文字列を出力するかどうかをテストするにはどうすればよいですか?
13 に答える
以前の質問では、ディレクトリにファイルがあるかどうかを確認する方法を尋ねました。次のコードはそれを実現しますが、より良い解決策についてはrsp の回答を参照してください。
空の出力
コマンドは値を返さず、出力します。コマンド置換を使用して、この出力を取得できます。例えば$(ls -A)
。次のように、Bash で空でない文字列をテストできます。
if [[ $(ls -A) ]]; then
echo "there are files"
else
echo "no files found"
fi
シンボリックな current ( ) および parent ( ) ディレクトリ エントリを省略しているため、-A
ではなくを使用したことに注意してください。-a
.
..
注:コメントで指摘されているように、コマンド置換は末尾の改行をキャプチャしません。したがって、コマンドが改行のみを出力する場合、置換は何もキャプチャせず、テストは false を返します。可能性は非常に低いですが、上記の例では 1 つの改行が有効なファイル名であるため、これは可能です! 詳細については、この回答を参照してください。
終了コード
コマンドが正常に完了したことを確認したい場合$?
は、最後のコマンドの終了コード (成功の場合はゼロ、失敗の場合はゼロ以外) を含む を調べることができます。例えば:
files=$(ls -A)
if [[ $? != 0 ]]; then
echo "Command failed."
elif [[ $files ]]; then
echo "Files found."
else
echo "No files found."
fi
詳細はこちら。
TL;DR
if [[ $(ls -A | head -c1 | wc -c) -ne 0 ]]; then ...; fi
私のオリジナルを改善するための提案をしてくれたnetjに感謝します:if [[ $(ls -A | wc -c) -ne 0 ]]; then ...; fi
これは古い質問ですが、改善または少なくとも明確化が必要なことが少なくとも 2 つあります。
最初の問題
私が目にする最初の問題は、ここで提供されている例のほとんどが単純に機能しないことです。ls -al
およびコマンドを使用しls -Al
ます。どちらも空のディレクトリに空でない文字列を出力します。これらの例では、ファイルがない場合でも常にファイルがあると報告されます。
そのため、単に使用する必要があります-とにかく、出力があるかどうかをテストするだけでよいのに、「長いリスト形式を使用する」ことを意味するスイッチをls -A
使用したいのはなぜですか?-l
したがって、ここでの答えのほとんどは単に間違っています。
第二の問題
2 番目の問題は、一部の回答は正常に機能しますが ( orを代わりに使用しないもの)、すべて次のようなことを行うことです。ls -al
ls -Al
ls -A
- コマンドを実行する
- 出力全体を RAM にバッファリングする
- 出力を巨大な単一行の文字列に変換します
- その文字列を空の文字列と比較します
代わりに私が提案することは次のとおりです。
- コマンドを実行する
- 保存せずに出力内の文字を数える
- またはさらに良い-最大1文字の数を数えます(このアイデアを以下のコメントに投稿してくれたnetj
using head -c1
に感謝します)
- またはさらに良い-最大1文字の数を数えます(このアイデアを以下のコメントに投稿してくれたnetj
- その数をゼロと比較する
たとえば、次の代わりに:
if [[ $(ls -A) ]]
私は使うだろう:
if [[ $(ls -A | wc -c) -ne 0 ]]
# or:
if [[ $(ls -A | head -c1 | wc -c) -ne 0 ]]
それ以外の:
if [ -z "$(ls -lA)" ]
私は使うだろう:
if [ $(ls -lA | wc -c) -eq 0 ]
# or:
if [ $(ls -lA | head -c1 | wc -c) -eq 0 ]
等々。
出力が小さい場合は問題にならないかもしれませんが、出力が大きい場合はその差が大きくなる可能性があります。
$ time [ -z "$(seq 1 10000000)" ]
real 0m2.703s
user 0m2.485s
sys 0m0.347s
それを比較してください:
$ time [ $(seq 1 10000000 | wc -c) -eq 0 ]
real 0m0.128s
user 0m0.081s
sys 0m0.105s
そしてさらに良い:
$ time [ $(seq 1 10000000 | head -c1 | wc -c) -eq 0 ]
real 0m0.004s
user 0m0.000s
sys 0m0.007s
完全な例
Will Vousden による回答からの更新された例:
if [[ $(ls -A | wc -c) -ne 0 ]]; then
echo "there are files"
else
echo "no files found"
fi
netjによる提案の後、再度更新されました:
if [[ $(ls -A | head -c1 | wc -c) -ne 0 ]]; then
echo "there are files"
else
echo "no files found"
fi
jakeonfireによる追加の更新:
grep
一致しない場合、失敗して終了します。これを利用して、構文を少し単純化できます。
if ls -A | head -c1 | grep -E '.'; then
echo "there are files"
fi
if ! ls -A | head -c1 | grep -E '.'; then
echo "no files found"
fi
空白の破棄
テストしているコマンドが、空の文字列として扱いたい空白を出力する可能性がある場合は、代わりに次のようにします。
| wc -c
あなたが使用することができます:
| tr -d ' \n\r\t ' | wc -c
またはでhead -c1
:
| tr -d ' \n\r\t ' | head -c1 | wc -c
またはそのようなもの。
概要
まず、機能するコマンドを使用します。
次に、不要な RAM への保存と、潜在的に巨大なデータの処理を避けます。
回答では、出力が常に小さいとは指定されていないため、出力が大きくなる可能性も考慮する必要があります。
if [ -z "$(ls -lA)" ]; then
echo "no files found"
else
echo "There are files"
fi
これにより、コマンドが実行され、返された出力 (文字列) の長さがゼロかどうかがチェックされます。他のフラグについては、 'test' マニュアル ページを確認してください。
チェックする引数を "" で囲みます。そうしないと、(チェックする) 2 番目の引数が指定されていないため、結果が空の場合に構文エラーが発生します。
注: はls -la
常に返されるため.
、..
それを使用しても機能しません。ls のマニュアル ページを参照してください。また、これは便利そうで簡単そうに見えて、壊れやすいのではないでしょうか。結果に応じて 0 または 1 を返す小さなスクリプト/アプリケーションを作成すると、はるかに信頼性が高くなります!
エレガントでバージョンに依存しない bash ソリューション (実際には、他の最新のシェルでも動作するはずです) が必要な人や、簡単な作業にワンライナーを使用するのが好きな人向けです。どうぞ!
ls | grep . && echo 'files found' || echo 'files not found'
(言及されたコメントの1つとして注意してくださいls -al
。実際、すべてが何かを返すので、私の答えではシンプルを使用し-l
ます-a
ls
6.4 Bashの条件式
-z string
True if the length of string is zero.
-n string
string
True if the length of string is non-zero.
省略版を使用できます:
if [[ $(ls -A) ]]; then
echo "there are files"
else
echo "no files found"
fi
Jon Lin がコメントしたように、ls -al
常に出力されます ( for .
and ..
)。ls -Al
これら 2 つのディレクトリは避けたいと考えています。
たとえば、コマンドの出力をシェル変数に入れることができます。
v=$(ls -Al)
古い、入れ子にできない表記法は次のとおりです。
v=`ls -Al`
しかし、私はネスト可能な表記法を好み$(
ます...)
その変数が空でないかどうかをテストできます
if [ -n "$v" ]; then
echo there are files
else
echo no files
fi
そして、両方を次のように組み合わせることができますif [ -n "$(ls -Al)" ]; then
場合によってls
は、いくつかのシェルエイリアスである可能性があります。を使用することをお勧めします$(/bin/ls -Al)
。ls(1)、hier(7)、environ(7)、およびあなた~/.bashrc
(シェルがGNU bashの場合、私の対話型シェルはzshで定義されている/etc/passwd
- passwd(5)およびchsh(1)を参照) を参照してください。
コマンドの出力が必要だと思うls -al
ので、bashでは次のようになります。
LS=`ls -la`
if [ -n "$LS" ]; then
echo "there are files"
else
echo "no files found"
fi