Bashスクリプト:空のディレクトリのテスト


95

ディレクトリにファイルが含まれていないかどうかをテストします。もしそうなら、いくつかの処理をスキップします。

私は次を試しました:

if [ ./* == "./*" ]; then
    echo "No new file"
    exit 1
fi

次のエラーが発生します。

line 1: [: too many arguments

解決策/代替案はありますか?


回答:


121
if [ -z "$(ls -A /path/to/dir)" ]; then
   echo "Empty"
else
   echo "Not Empty"
fi

また、以前にディレクトリが存在するかどうかを確認するのもいいでしょう。


11
使用しないでください&&||同時に!場合はecho "Not Empty"失敗し、echo "Empty"実行されます!やってみてecho "test" && false || echo "fail"!はい、echo失敗しないことはわかっていますが、他のコマンドを変更した場合は、驚くでしょう!
-uzsolt

4
上記のコードが機能しない場合、少なくとも1つの例を提供してください。具体的には、このコードは完全に正しいです。私はアスカーは彼自身の目的のためにこれを適応させることが可能であることを願っています
アンドレイAtapin

3
[ "$(ls -A /)" ] && touch /non-empty || echo "Empty"-という名前の作成されたファイルで空でないディレクトリを「マーク」したい場合non-emptyは失敗し、「空」を出力します。
ウズソルト

4
どこにtouch /empty私のラインに?
アンドレイアタピン

7
大野!このコードには非常に重要な問題があります。それはする必要がありif [ -n "$(ls -A /path/to/dir)" ]; then、誰かがどこかで自分のサーバーにこのコードを貼り付けし、ハッカーがそれを悪用する方法を数字の前に...答えを更新してください。場合は/path/to/dir空ではない、そこのファイル名を引数として渡されます/bin/test明確に意図されていません。-n引数を追加するだけで問題は解決しました。ありがとう!
エドワードネッドハーベイ

21

何もカウントする必要もシェルグロブも必要ありません。readと組み合わせて使用することもできますfind。場合findの出力が空である、あなたは戻りますfalse

if find /some/dir -mindepth 1 | read; then
   echo "dir not empty"
else
   echo "dir empty"
fi

これはポータブルでなければなりません。


ニースのソリューションが、私はあなたの考えるecho呼び出しが間違った結果を反映:(Cygwinの下)私のテストではfind . -mindepth 1 | read、空でないディレクトリに141エラーコードを持っていて、空のディレクトリで0
ルーカスザシモン

@LucasCimonここにはありません(macOSおよびGNU / Linux)。空でないディレクトリに対して、read0を返し、空のため、1
slhck

1
PSAは動作しませんset -o pipefail
大佐三十二

19
if [ -n "$(find "$DIR_TO_CHECK" -maxdepth 0 -type d -empty 2>/dev/null)" ]; then
    echo "Empty directory"
else
    echo "Not empty or NOT a directory"
fi

正確かつ迅速。いいね!
l0b0

4
引用符(2x)とテスト-nを正しく安全に行う必要があります(名前にスペースが含まれるディレクトリでテストし、名前が '0 = 1'の空でないディレクトリでテストします)。... [ -n "$(find "$DIR_TO_CHECK" -maxdepth 0 -type d -empty 2>/dev/null)" ]; ...
ズリン

1
@ivan_pozdeevそれは、少なくともGNU findには当てはまりません。あなたは考えているかもしれませんgrepserverfault.com/questions/225798/...
ウラジミールPanteleev

を記述しfind "$DIR_TO_CHECK" -maxdepth 0 -type d -empty | grep .、grepの終了ステータスに依存する方が簡単かもしれません。どちらにしても、これはこの質問に対する非常に正しい答えです。
トムアンダーソン

13
#!/bin/bash
if [ -d /path/to/dir ]; then
    # the directory exists
    [ "$(ls -A /path/to/dir)" ] && echo "Not Empty" || echo "Empty"
else
    # You could check here if /path/to/dir is a file with [ -f /path/to/dir]
fi

4
それだけでなければなりません。ls出力を解析する必要はありません。単に空かどうかを確認してください。findを使用することは、私にとってやり過ぎのように感じます。
アコスタディノフ

4

これにより、現在の作業ディレクトリ(。)でジョブが実行されます。

[ `ls -1A . | wc -l` -eq 0 ] && echo "Current dir is empty." || echo "Current dir has files (or hidden files) in it."

または、同じコマンドを読みやすくするために3行に分割します。

[ `ls -1A . | wc -l` -eq 0 ] && \
echo "Current dir is empty." || \
echo "Current dir has files (or hidden files) in it."

別のターゲットフォルダーで実行する必要ls -1A . | wc -lがあるls -1A <target-directory> | wc -l場合は、に置き換え てください。

編集:に置き換え-1aました-1A(@Danielコメントを参照)


2
ls -A代わりに使用してください。一部のファイルシステムには、ドキュメントによる...シンボリックリンクがありません。
ダニエルベック

1
@Danielに感謝します。私はあなたの提案の後、答えを編集しました。「1」も削除される可能性があります。
ztank1013

2
害はありませんが、端末に出力しない場合は暗示されます。別のプログラムにパイプするので、冗長です。
ダニエルベック

-1間違いなく冗長です。lsパイプされるときに行ごとに1つの項目を印刷しない場合でも、0行以上の行が生成されたかどうかを確認するという考え方には影響しません。
ビクターヤレマ

3

以下を使用します。

count="$( find /path -mindepth 1 -maxdepth 1 | wc -l )"
if [ $count -eq 0 ] ; then
   echo "No new file"
   exit 1
fi

このように、あなたはの出力フォーマットから独立していますls-mindepthディレクトリ自体をスキップし、-maxdepth再帰的にサブディレクトリに防御して物事を高速化することを防ぎます。


もちろん、現在は出力形式に依存しwc -lていfindます(ただし、これはかなり合理的です)。
ダニエルベック

3

配列を使用する:

files=( * .* )
if (( ${#files[@]} == 2 )); then
    # contents of files array is (. ..)
    echo dir is empty
fi

3
非常に良い解決策ですが、それが必要であることに注意してくださいshopt -s nullglob
-xebeche

3
この${#files[@]} == 2仮定はルートディレクトリを表していません(おそらく空であるかどうかはテストしませんが、その制限を知らないコードはそうするかもしれません)。
-ivan_pozdeev

3

ハッキリですが、bashのみ、PIDフリーの方法:

is_empty() {
    test -e "$1/"* 2>/dev/null
    case $? in
        1)   return 0 ;;
        *)   return 1 ;;
    esac
}

これはtest-e:の後に複数の引数が与えられた場合、ビルトインが2で終了するという事実を利用しています。まず、"$1"/*globはbashによって展開されます。これにより、ファイルごとに1つの引数が生成されます。そう

  • ファイルが存在しない場合、アスタリスクtest -e "$1"*は展開されないため、シェル*は1 という名前のファイルの試行にフォールバックします。

  • ...ただし、実際に正確*に名前が付けられたファイルが1つある場合を除き、アスタリスクはアスタリスクに展開され、上記と同じ呼び出しになります。test -e "dir/*"、今度は0を返します(これを指摘してくれた@TrueYに感謝します)。

  • ファイルが1つある場合、test -e "dir/file"実行され、0が返されます。

  • ただし、1より多くのファイルがある場合test -e "dir/file1" "dir/file2" は実行され、bashはそれを使用エラー、つまり2として報告します。

case ロジック全体をラップして、最初のケースのみが終了ステータス1で成功として報告されるようにします。

私がチェックしていない可能性のある問題:

  • 許可された引数の数よりも多くのファイルがあります。これは、2 +ファイルの場合と同様に動作する可能性があります。

  • または、実際には空の名前のファイルがあります-健全なOS / FSでそれが可能かどうかはわかりません。


1
軽微な修正:dir /にファイルがない場合は、test -e dir/*が呼び出されます。dir内のファイルが「*」のみの場合、testは0を返します。さらにファイルがある場合は、2を返します。したがって、説明どおりに機能します。
-TrueY

あなたは正しいです、@ TrueY、私は答えにそれを取り入れました。ありがとう!
アロイスマーダル

2

FIND(1)(LinuxおよびFreeBSDの場合)を使用すると、「-maxdepth 0」でディレクトリエントリを非再帰的に検索し、「-empty」で空かどうかをテストできます。これが与える質問に適用:

if test -n "$(find ./ -maxdepth 0 -empty)" ; then
    echo "No new file"
    exit 1
fi

100%ポータブルではないかもしれませんが、エレガントです。
クレイグリンガー

1

最良の解決策は次のとおりです。

files=$(shopt -s nullglob; shopt -s dotglob; echo /MYPATH/*)
[[ "$files" ]] || echo "dir empty" 

https://stackoverflow.com/a/91558/520567に感謝

これは私の答えを匿名で編集したもので、誰かに役立つ場合と役に立たない場合があります。わずかな変更でファイルの数が決まります。

files=$(shopt -s nullglob dotglob; s=(MYPATH/*); echo ${s[*]}) 
echo "MYPATH contains $files files"

ファイル名にスペースが含まれている場合でも、これは正しく機能します。


1
if find "${DIR}" -prune ! -empty -exit 1; then
    echo Empty
else
    echo Not Empty
fi

編集:このソリューションは、実装を簡単に見てから、gnu findでうまく機能すると思います。しかし、これは、たとえばnetbsdのfindでは機能しない場合があります。実際、その1つはstat(2)のst_sizeフィールドを使用します。マニュアルでは次のように説明しています。

st_size            The size of the file in bytes.  The meaning of the size
                   reported for a directory is file system dependent.
                   Some file systems (e.g. FFS) return the total size used
                   for the directory metadata, possibly including free
                   slots; others (notably ZFS) return the number of
                   entries in the directory.  Some may also return other
                   things or always report zero.

より良い解決策は、より簡単です:

if find "${DIR}" -mindepth 1 -exit 1; then
    echo Empty
else
    echo Not Empty
fi

また、最初のソリューションの-pruneは役に立ちません。

編集:gnu findの-exitはありません。上記のソリューションはNetBSDのfindに適しています。GNU findの場合、これは機能するはずです。

if [ -z "`find \"${DIR}\" -mindepth 1 -exec echo notempty \; -quit`" ]; then
    echo Empty
else
    echo Not Empty
fi

GNU findutils 4.6.0からの検索(最新バージョン)に-exit述語がありません
デニス

0

これはすべて素晴らしいものです。スクリプトにしただけで、現在のディレクトリの下の空のディレクトリを確認できます。以下は、「findempty」というファイルに入れて、bashがそれを見つけられるようにパスに配置し、chmod 755を実行する必要があります。特定のニーズに合わせて簡単に修正できると思います。

#!/bin/bash
if [ "$#" == "0" ]; then 
find . -maxdepth 1 -type d -exec findempty "{}"  \;
exit
fi

COUNT=`ls -1A "$*" | wc -l`
if [ "$COUNT" == "0" ]; then 
echo "$* : $COUNT"
fi

0

これ../INは、スクリプトがディレクトリにあることを考慮して、ディレクトリ内のファイルをチェックして処理するために役立ちます../Script

FileTotalCount=0

    for file in ../IN/*; do
    FileTotalCount=`expr $FileTotalCount + 1`
done

if test "$file" = "../IN/*"
then

    echo "EXITING: NO files available for processing in ../IN directory. "
    exit

else

  echo "Starting Process: Found ""$FileTotalCount"" files in ../IN directory for processing."

# Rest of the Code

0

1つのifステートメントにディレクトリが存在し、空でない場合のテストについてはどうですか

if [[ -d path/to/dir && -n "$(ls -A path/to/dir)" ]]; then 
  echo "directory exists"
else
  echo "directory doesn't exist"
fi

-1

現在のディレクトリ以外のディレクトリについては、空でないディレクトリでは失敗するrmdirことrmdirが保証されているため、試してみて空かどうかを確認できます。場合はrmdir成功し、あなたが実際には、空のディレクトリがテストを生き残るために望んでいたmkdirことを再度。

一時的に存在しなくなることを知っているディレクトリによって混乱する可能性のある他のプロセスがある場合は、このハックを使用しないでください。

場合はrmdir、あなたのために動作しませんし、あなたが潜在的に大量のファイルが含まれている可能性がディレクトリをテストすることがあり、シェルグロブに依存するすべてのソリューションが遅く取得および/またはコマンドラインの長さ制限に実行することができます。findその場合はおそらく使用した方が良いでしょう。find私が考えることができる最速のソリューションは次のようになります

is_empty() {
    test -z $(find "$1" -mindepth 1 -printf X -quit)
}

これは、GNUおよびBSDバージョンでは機能しますfindが、Solaris バージョンでは機能しませんfind。オラクル、あなたの仕事が大好きです。


良い考えではありません。OPは、ディレクトリが空かどうかをテストするだけでした。
ロアイマ

-3

ディレクトリを削除して、エラーを待つことができます。 rmdirは、空でないディレクトリを削除しません。

_path="some/path"
if rmdir $_path >/dev/null 2>&1; then
   mkdir $_path        # create it again
   echo "Empty"
else
   echo "Not empty or doesn't exist"
fi

3
-1これは裏目に出る種類のコードです。rmdirディレクトリを削除する権限がない場合は失敗します。または、Btrfsサブボリュームの場合; または、読み取り専用ファイルシステムに属している場合。そして、rmdir失敗せずにmkdir実行される場合:既に削除されたディレクトリが別のユーザーに属している場合はどうなりますか?その(おそらく非標準の)パーミッションはどうですか?ACL?拡張属性?すべてが失われました。
カミルマシオロウスキ

まあ、私はbashを学んでいるだけで、すべてのディレクトリを反復処理するよりも高速な方法になると考えましたが、CPUは強力であり、安全ではありません。
impxd
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.