シェルスクリプトからディレクトリにファイルが含まれているかどうかを確認する
質問
シェル スクリプトから、ディレクトリにファイルが含まれているかどうかを確認するにはどうすればよいですか?
これに似たもの
if [ -e /some/dir/* ]; then echo "huzzah"; fi;
ただし、これはディレクトリに 1 つまたは複数のファイルが含まれている場合に機能します (上記の方法は、ファイルが 0 つまたは 1 つだけの場合にのみ機能します)。
解決
これまでのソリューションでは、 ls
. 。すべて bash のソリューションは次のとおりです。
#!/bin/bash
shopt -s nullglob dotglob # To include hidden files
files=(/some/dir/*)
if [ ${#files[@]} -gt 0 ]; then echo "huzzah"; fi
他のヒント
ベスト 3 つのトリック
shopt -s nullglob dotglob; f=your/dir/*; ((${#f}))
このトリックは100%です bash
そしてサブシェルを呼び出します(生成します)。アイデアの由来は、 ブルーノ・デ・フレイン そして改善されました チームボブさんのコメント。
files=$(shopt -s nullglob dotglob; echo your/dir/*)
if (( ${#files} ))
then
echo "contains files"
else
echo "empty (or does not exist or is a file)"
fi
注記: 空のディレクトリと存在しないディレクトリの間に違いはありません (指定されたパスがファイルの場合でも)。
同様の代替手段と詳細 (およびより多くの例) があります。 '正式' #bash IRC チャネルに関するよくある質問:
if (shopt -s nullglob dotglob; f=(*); ((${#f[@]})))
then
echo "contains files"
else
echo "empty (or does not exist, or is a file)"
fi
[ -n "$(ls -A your/dir)" ]
このトリックは以下からインスピレーションを受けています nixCraftの記事 2007年に投稿されました。追加 2>/dev/null
出力エラーを抑制するには "No such file or directory"
.
こちらも参照 アンドリュー・テイラーの答え(2008)と gr8can8dianの答え(2011)。
if [ -n "$(ls -A your/dir 2>/dev/null)" ]
then
echo "contains files (or is a file)"
else
echo "empty (or does not exist)"
fi
または 1 行の bashism バージョン:
[[ $(ls -A your/dir) ]] && echo "contains files" || echo "empty"
注記: ls
戻り値 $?=2
ディレクトリが存在しない場合。ただし、ファイルと空のディレクトリの間に違いはありません。
[ -n "$(find your/dir -prune -empty)" ]
この最後のトリックは以下からインスピレーションを受けています。 グラブスターの答え どこ -maxdepth 0
に置き換えられます -prune
そして改善されました フィルスさんのコメント。
if [ -n "$(find your/dir -prune -empty 2>/dev/null)" ]
then
echo "empty (directory or file)"
else
echo "contains files (or does not exist)"
fi
を使ったバリエーション -type d
:
if [ -n "$(find your/dir -prune -empty -type d 2>/dev/null)" ]
then
echo "empty directory"
else
echo "contains files (or does not exist or is not a directory)"
fi
説明:
find -prune
よりも似ていますfind -maxdepth 0
使用する文字数を減らすfind -empty
空のディレクトリとファイルを出力しますfind -type d
ディレクトリのみを出力します
注記: 交換することもできます [ -n "$(find your/dir -prune -empty)" ]
以下の短縮版だけで:
if [ `find your/dir -prune -empty 2>/dev/null` ]
then
echo "empty (directory or file)"
else
echo "contains files (or does not exist)"
fi
この最後のコードはほとんどの場合に機能しますが、悪意のあるパスがコマンドを表現する可能性があることに注意してください。
次のような場合はどうでしょうか。
if find /some/dir/ -maxdepth 0 -empty | read v; then echo "Empty dir"; fi
この方法では、ディレクトリの内容の完全なリストを生成する必要がありません。の read
これは、出力を破棄することと、何かが読み取られた場合にのみ式を true に評価することの両方です (つまり、 /some/dir/
によって空が見つかりました find
).
試す:
if [ ! -z `ls /some/dir/*` ]; then echo "huzzah"; fi
# Works on hidden files, directories and regular files
### isEmpty()
# This function takes one parameter:
# $1 is the directory to check
# Echoes "huzzah" if the directory has files
function isEmpty(){
if [ "$(ls -A $1)" ]; then
echo "huzzah"
else
echo "has no files"
fi
}
大量のファイルが含まれるディレクトリには注意してください。評価には時間がかかる場合があります ls
指示。
IMO の最良のソリューションは、
find /some/dir/ -maxdepth 0 -empty
DIR="/some/dir"
if [ "$(ls -A $DIR)" ]; then
echo 'There is something alive in here'
fi
これの出力を比較していただけますか?
ls -A /some/dir | wc -l
# Checks whether a directory contains any nonhidden files. # # usage: if isempty "$HOME"; then echo "Welcome home"; fi # isempty() { for _ief in $1/*; do if [ -e "$_ief" ]; then return 1 fi done return 0 }
実装に関する注意事項:
- の
for
ループは外部への呼び出しを回避しますls
プロセス。すべてのディレクトリ エントリを 1 回読み取ります。これを最適化するには、readdir() を明示的に使用する C プログラムを作成する必要があります。 - の
test -e
ループ内で空のディレクトリの場合をキャッチします。この場合、変数は_ief
値「somedir/*」が割り当てられます。そのファイルが存在する場合にのみ、関数は「空でない」を返します。 - この関数はすべての POSIX 実装で動作します。ただし、Solaris /bin/sh はそのカテゴリに分類されないことに注意してください。その
test
実装ではサポートされていません-e
フラグ。
これにより、ディレクトリが空かどうか、そうでない場合はそこに含まれるファイルの数がわかります。
directory="/some/dir"
number_of_files=$(ls -A $directory | wc -l)
if [ "$number_of_files" == "0" ]; then
echo "directory $directory is empty"
else
echo "directory $directory contains $number_of_files files"
fi
これは非常に遅い応答かもしれませんが、機能する解決策を次に示します。この行はファイルの存在のみを認識します。ディレクトリが存在する場合、誤検知は発生しません。
if find /path/to/check/* -maxdepth 0 -type f | read
then echo "Files Exist"
fi
私は驚いています 空のディレクトリに関する Wooledge ガイド 言及されていない。このガイド、そして実際に Wooledge のすべては、シェル タイプの質問については必読です。
そのページからの注目点:
ls 出力を解析しないでください。ls -A ソリューションでも壊れる可能性があります (例:HP -uxでは、あなたがrootである場合、ls -aはあなたがルートではない場合にそれが何をするかの正反対を行います - そして、私は信じられないほど愚かなものを作ることができません)。
実際、直接的な質問をまったく避けたいと思う人もいるかもしれません。通常、人々は、そのファイルなどを含む何かをしたいので、ディレクトリが空であるかどうかを知りたいと思っています。より大きな質問を見てください。たとえば、次の検索ベースの例の 1 つが適切な解決策となる可能性があります。
# Bourne
find "$somedir" -type f -exec echo Found unexpected file {} \;
find "$somedir" -maxdepth 0 -empty -exec echo {} is empty. \; # GNU/BSD
find "$somedir" -type d -empty -exec cp /my/configfile {} \; # GNU/BSD
最も一般的に、実際に必要なのは次のようなものだけです。
# Bourne
for f in ./*.mpg; do
test -f "$f" || continue
mympgviewer "$f"
done
言い換えれば、質問をする人は、mympgviewerのようなエラーメッセージを回避するために明示的な空の方向テストが必要であると考えたかもしれません。./*.mpg:実際にそのようなテストが不要な場合、そのようなファイルやディレクトリはありません。
dir_is_empty() {
[ "${1##*/}" = "*" ]
}
if dir_is_empty /some/dir/* ; then
echo "huzzah"
fi
という名前のファイルがないと仮定します。 *
の中へ /any/dir/you/check
, 、それはうまくいくはずです bash
dash
posh
busybox sh
そして zsh
ただし (zsh の場合) が必要です unsetopt nomatch
.
パフォーマンスは他のものと同等でなければなりません ls
使用するもの *
(glob)、多くのノードを含むディレクトリでは遅いと思います (私の /usr/bin
3000以上のファイルではそれほど遅くはありませんでした)、すべてのディレクトリ/ファイル名(およびそれ以上)が引数として関数に渡される(解決される)ため、少なくともすべてのディレクトリ/ファイル名(およびそれ以上)を割り当てるのに十分なメモリを使用します。一部のシェルにはおそらく引数の数に制限があり、 /または引数の長さ。
ディレクトリが空かどうかを確認するポータブルな高速 O(1) ゼロ リソースの方法があれば便利です。
アップデート
上記のバージョンでは、追加のテストが必要な場合に備えて、隠しファイル/ディレクトリは考慮されていません。 is_empty
から Rich の sh (POSIX シェル) のトリック:
is_empty () (
cd "$1"
set -- .[!.]* ; test -f "$1" && return 1
set -- ..?* ; test -f "$1" && return 1
set -- * ; test -f "$1" && return 1
return 0 )
しかし、その代わりに、私は次のようなことを考えています。
dir_is_empty() {
[ "$(find "$1" -name "?*" | dd bs=$((${#1}+3)) count=1 2>/dev/null)" = "$1" ]
}
悲しいことに、ディレクトリが空の場合の引数と検索出力との末尾のスラッシュの違い、および末尾の改行についての懸念があります(ただし、これは簡単に処理できるはずです)。 busybox
sh
おそらくバグであるものを表示します find -> dd
出力がランダムに切り捨てられたパイプ (使用した場合) cat
出力は常に同じのようです dd
引数付き count
).
小さなバリエーション ブルーノの答え:
files=$(ls -1 /some/dir| wc -l)
if [ $files -gt 0 ]
then
echo "Contains files"
else
echo "Empty"
fi
わたしにはできる
ZSH
質問が bash 用にマークされていることは知っています。ただし、参考までに、 zsh ユーザー:
空でないディレクトリをテストする
かどうかを確認するには foo
空ではない:
$ for i in foo(NF) ; do ... ; done
どこで、もし foo
が空ではない場合、 for
ブロックが実行されます。
空のディレクトリをテストする
かどうかを確認するには foo
は空です:
$ for i in foo(N/^F) ; do ... ; done
どこで、もし foo
が空の場合、内のコードは for
ブロックが実行されます。
ノート
ディレクトリを引用する必要はありませんでした foo
上記のようになりますが、必要に応じてそうすることもできます。
$ for i in 'some directory!'(NF) ; do ... ; done
ディレクトリでなくても、複数のオブジェクトをテストすることもできます。
$ mkdir X # empty directory
$ touch f # regular file
$ for i in X(N/^F) f(N/^F) ; do echo $i ; done # echo empty directories
X
ディレクトリではないものはすべて無視されます。
エクストラ
グロブしているため、任意のグロブ (または中括弧の展開) を使用できます。
$ mkdir X X1 X2 Y Y1 Y2 Z
$ touch Xf # create regular file
$ touch X1/f # directory X1 is not empty
$ touch Y1/.f # directory Y1 is not empty
$ ls -F # list all objects
X/ X1/ X2/ Xf Y/ Y1/ Y2/ Z/
$ for i in {X,Y}*(N/^F); do printf "$i "; done; echo # print empty directories
X X2 Y Y2
配列に配置されたオブジェクトを調べることもできます。上記のようなディレクトリの場合、たとえば次のようになります。
$ ls -F # list all objects
X/ X1/ X2/ Xf Y/ Y1/ Y2/ Z/
$ arr=(*) # place objects into array "arr"
$ for i in ${^arr}(N/^F); do printf "$i "; done; echo
X X2 Y Y2 Z
したがって、配列パラメータにすでに設定されている可能性のあるオブジェクトをテストできます。
のコードに注意してください。 for
block は、明らかに、すべてのディレクトリで順番に実行されます。これが望ましくない場合は、単に配列パラメータを設定し、そのパラメータを操作することができます。
$ for i in *(NF) ; do full_directories+=($i) ; done
$ do_something $full_directories
説明
zsh ユーザーの場合は、 (F)
glob 修飾子 (「 man zshexpn
)、これは「完全な」(空ではない) ディレクトリに一致します。
$ mkdir X Y
$ touch Y/.f # Y is now not empty
$ touch f # create a regular file
$ ls -dF * # list everything in the current directory
f X/ Y/
$ ls -dF *(F) # will list only "full" directories
Y/
予選 (F)
一致するオブジェクトをリストします。はディレクトリであり、かつ空ではありません。それで、 (^F)
一致します:ディレクトリではないか、空です。したがって、 (^F)
たとえば、単独で通常のファイルもリストされます。したがって、上で説明したように、 zshexp
man ページ、また必要です (/)
ディレクトリのみをリストする glob 修飾子:
$ mkdir X Y Z
$ touch X/f Y/.f # directories X and Y now not empty
$ for i in *(/^F) ; do echo $i ; done
Z
したがって、指定されたディレクトリが空かどうかを確認するには、次のコマンドを実行します。
$ mkdir X
$ for i in X(/^F) ; do echo $i ; done ; echo "finished"
X
finished
空ではないディレクトリがキャプチャされないことを確認するために、次のようにします。
$ mkdir Y
$ touch Y/.f
$ for i in Y(/^F) ; do echo $i ; done ; echo "finished"
zsh: no matches found: Y(/^F)
finished
おっとっと!以来 Y
は空ではありません。zsh は一致するものを見つけません (/^F)
(「空のディレクトリ」)そのため、グロブに一致するものが見つからなかったというエラー メッセージが出力されます。したがって、これらの考えられるエラー メッセージを抑制する必要があります。 (N)
グロブ修飾子:
$ mkdir Y
$ touch Y/.f
$ for i in Y(N/^F) ; do echo $i ; done ; echo "finished"
finished
したがって、空ではないディレクトリの場合は修飾子が必要です。 (N/^F)
, これは次のように読むことができます。「失敗やディレクトリがいっぱいではないことについて警告しないでください。」
同様に、空のディレクトリの場合は修飾子が必要です。 (NF)
, これも同様に次のように読むことができます。「失敗については警告しないでください。ディレクトリがいっぱいです。」
if ls /some/dir/* >/dev/null 2>&1 ; then echo "huzzah"; fi;
これまでのところ、grep を使用した答えは見たことがありません。これなら、より簡単な答えが得られると思います(あまりにも多くの奇妙な記号を使用しないでください!)。ボーンシェルを使用してディレクトリにファイルが存在するかどうかを確認する方法は次のとおりです。
これはディレクトリ内のファイルの数を返します。
ls -l <directory> | egrep -c "^-"
ディレクトリが書かれている場所にディレクトリパスを入力できます。パイプの前半では、各ファイルの出力の最初の文字が「-」になるようにします。次に、EGREPは、正規表現を使用してそのシンボルから始まる線の数をカウントします。あとは、取得した数値を保存し、次のような逆引用符を使用して比較するだけです。
#!/bin/sh
fileNum=`ls -l <directory> | egrep -c "^-"`
if [ $fileNum == x ]
then
#do what you want to do
fi
x は任意の変数です。
プルーンなことと最後の答えを混ぜ合わせて、私はこうなりました
find "$some_dir" -prune -empty -type d | read && echo empty || echo "not empty"
スペースを含むパスでも機能します
簡単な答え バッシュ:
if [[ $(ls /some/dir/) ]]; then echo "huzzah"; fi;
私なら行きます find
:
if [ -z "$(find $dir -maxdepth 1 -type f)" ]; then
echo "$dir has NO files"
else
echo "$dir has files"
これにより、サブディレクトリを経由せずに、ディレクトリ内のファイルのみを検索する出力がチェックされます。次に、次を使用して出力をチェックします。 -z
から取られたオプション man test
:
-z STRING
the length of STRING is zero
いくつかの結果を参照してください。
$ mkdir aaa
$ dir="aaa"
空のディレクトリ:
$ [ -z "$(find aaa/ -maxdepth 1 -type f)" ] && echo "empty"
empty
その中にディレクトリを入れるだけです:
$ mkdir aaa/bbb
$ [ -z "$(find aaa/ -maxdepth 1 -type f)" ] && echo "empty"
empty
ディレクトリ内のファイル:
$ touch aaa/myfile
$ [ -z "$(find aaa/ -maxdepth 1 -type f)" ] && echo "empty"
$ rm aaa/myfile
サブディレクトリ内のファイル:
$ touch aaa/bbb/another_file
$ [ -z "$(find aaa/ -maxdepth 1 -type f)" ] && echo "empty"
empty
findコマンドで試してみます。ディレクトリをハードコーディングするか、引数として指定します。次に、検索を開始して、ディレクトリ内のすべてのファイルを検索します。find の戻り値が null かどうかを確認します。findのデータをエコーする
#!/bin/bash
_DIR="/home/user/test/"
#_DIR=$1
_FIND=$(find $_DIR -type f )
if [ -n "$_FIND" ]
then
echo -e "$_DIR contains files or subdirs with files \n\n "
echo "$_FIND"
else
echo "empty (or does not exist)"
fi
いくつかの回避策を使えば、ディレクトリにファイルがあるかどうかを確認する簡単な方法を見つけることができました。これを grep コマンドでさらに拡張し、特に .xml や .txt ファイルなどをチェックすることができます。元 : ls /some/dir | grep xml | wc -l | grep -w "0"
#!/bin/bash
if ([ $(ls /some/dir | wc -l | grep -w "0") ])
then
echo 'No files'
else
echo 'Found files'
fi
私は嫌いです ls - A
解決策が掲載されました。おそらく、ディレクトリを削除したくないため、ディレクトリが空かどうかをテストしたいと思うでしょう。以下はそれを行います。ただし、空のファイルをログに記録したいだけの場合は、無限のファイルをリストするよりも、ファイルを削除して再作成するほうが早いでしょう?
これはうまくいくはずです...
if ! rmdir ${target}
then
echo "not empty"
else
echo "empty"
mkdir ${target}
fi
特定のターゲット ディレクトリをテストするには
if [ -d $target_dir ]; then
ls_contents=$(ls -1 $target_dir | xargs);
if [ ! -z "$ls_contents" -a "$ls_contents" != "" ]; then
echo "is not empty";
else
echo "is empty";
fi;
else
echo "directory does not exist";
fi;
これは私にとってはうまくいきます(dirが存在する場合):
some_dir="/some/dir with whitespace & other characters/"
if find "`echo "$some_dir"`" -maxdepth 0 -empty | read v; then echo "Empty dir"; fi
フルチェックの場合:
if [ -d "$some_dir" ]; then
if find "`echo "$some_dir"`" -maxdepth 0 -empty | read v; then echo "Empty dir"; else "Dir is NOT empty" fi
fi