322

コマンドが空の文字列を出力するかどうかをテストするにはどうすればよいですか?

4

13 に答える 13

401

以前の質問では、ディレクトリにファイルがあるかどうかを確認する方法を尋ねました。次のコードはそれを実現しますが、より良い解決策については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

詳細はこちら

于 2012-08-27T07:00:15.340 に答える
110

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 -alls -Alls -A

  1. コマンドを実行する
  2. 出力全体を RAM にバッファリングする
  3. 出力を巨大な単一行の文字列に変換します
  4. その文字列を空の文字列と比較します

代わりに私が提案することは次のとおりです。

  1. コマンドを実行する
  2. 保存せずに出力内の文字を数える
    • またはさらに良い-最大1文字の数を数えます(このアイデアを以下のコメントに投稿してくれたnetjusing head -c1
      に感謝します)
  3. その数をゼロと比較する

たとえば、次の代わりに:

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

またはそのようなもの。

概要

  1. まず、機能するコマンドを使用します

  2. 次に、不要な RAM への保存と、潜在的に巨大なデータの処理を避けます。

回答では、出力が常に小さいとは指定されていないため、出力が大きくなる可能性も考慮する必要があります。

于 2016-02-02T22:42:52.977 に答える
48
if [ -z "$(ls -lA)" ]; then
  echo "no files found"
else
  echo "There are files"
fi

これにより、コマンドが実行され、返された出力 (文字列) の長さがゼロかどうかがチェックされます。他のフラグについては、 'test' マニュアル ページを確認してください。

チェックする引数を "" で囲みます。そうしないと、(チェックする) 2 番目の引数が指定されていないため、結果が空の場合に構文エラーが発生します。

注: はls -la常に返されるため...それを使用しても機能しません。ls のマニュアル ページを参照してください。また、これは便利そうで簡単そうに見えて、壊れやすいのではないでしょうか。結果に応じて 0 または 1 を返す小さなスクリプト/アプリケーションを作成すると、はるかに信頼性が高くなります!

于 2012-08-27T07:00:34.193 に答える
32

エレガントでバージョンに依存しない bash ソリューション (実際には、他の最新のシェルでも動作するはずです) が必要な人や、簡単な作業にワンライナーを使用するのが好きな人向けです。どうぞ!

ls | grep . && echo 'files found' || echo 'files not found'

(言及されたコメントの1つとして注意してくださいls -al。実際、すべてが何かを返すので、私の答えではシンプルを使用し-lます-als

于 2014-08-26T01:12:50.543 に答える
22

バッシュリファレンスマニュアル

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
于 2014-05-08T04:25:39.587 に答える
16

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)を参照) を参照してください。

于 2012-08-27T07:00:29.917 に答える
5

コマンドの出力が必要だと思うls -alので、bashでは次のようになります。

LS=`ls -la`

if [ -n "$LS" ]; then
  echo "there are files"
else
  echo "no files found"
fi
于 2012-08-27T07:00:04.723 に答える