シェルスクリプトから、ディレクトリにファイルが含まれているかどうかを確認するにはどうすればよいですか?
これに似たもの
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
shopt -s nullglob dotglob; f=your/dir/*; ((${#f}))
このトリックは100%bash
であり、サブシェルを起動(スポーン)します。アイデアは Bruno De Fraine からのもので、 teambob のコメントによって改善されました。
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
注:空のディレクトリと存在しないディレクトリの間に違いはありません(そして、提供されたパスがファイルの場合でも)。
'official'FAQ for #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)" ]
このトリックは、2007年に投稿された nixCraftの記事 に触発されています。2>/dev/null
を追加して、出力エラー"No such file or directory"
を抑制します。
Andrew Taylor 's answer(2008)および gr8can8dian ' s answer(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)" ]
この最後のトリックは、 gravstar's answer からヒントを得たもので、-maxdepth 0
は-Prune
に置き換えられ、 phils のコメントによって改善されました。
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に評価します(つまり、find
によって/some/dir/
が空であることが検出された場合)。
試してください:
if [ ! -z `ls /some/dir/*` ]; then echo "huzzah"; fi
たくさんのファイルがあるディレクトリには注意してください! ls
コマンドの評価には時間がかかる場合があります。
IMOの最良の解決策は、
find /some/dir/ -maxdepth 0 -empty
# 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
}
DIR="/some/dir"
if [ "$(ls -A $DIR)" ]; then
echo 'There is something alive in here'
fi
これの出力を比較できますか?
ls -A /some/dir | wc -l
#ディレクトリに非表示でないファイルが含まれているかどうかを確認します。 # #使用法:if isempty "$ HOME";次に、「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/*"が割り当てられます。そのファイルが存在する場合のみ、関数は「空でない」を返します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
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
が必要です。
パフォーマンスは、*
(glob)を使用するすべてのls
に匹敵するはずです。多くのノードがあるディレクトリでは遅くなります(3000以上のファイルを持つ/usr/bin
はそれほど遅くなりません)、少なくともメモリを使用しますすべてのdirs/filenames(およびそれ以上)が引数として関数に渡される(解決される)ので、シェルの中にはおそらく引数の数や引数の長さに制限があるものがあります。
ディレクトリが空であるかどうかをチェックするポータブルで高速なO(1)ゼロリソースの方法は、便利です。
update
上記のバージョンでは、 Rich’s sh(POSIX Shell)tricks :からのis_empty
のように、さらにテストが必要な場合に、隠しファイル/ディレクトリを考慮していません。
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" ]
}
末尾のスラッシュに関するいくつかの懸念は、dirが空の場合の引数と検索出力の違い、および末尾の改行(ただし、これは扱いやすいはずです)、悲しいことに私のbusybox
sh
がfind -> dd
のおそらくバグを示しています出力がランダムに切り捨てられたパイプ(cat
を使用した場合、出力は常に同じで、引数dd
を持つcount
のようです)。
空のディレクトリに関する基本的なガイド が言及されていないことに驚いています。このガイド、および実際にすべてのwooledgeは、Shellタイプの質問に必読です。
そのページの注意事項:
Ls出力を解析しようとしないでください。 ls -Aソリューションでさえ壊れる可能性があります(たとえば、HP-UXでは、rootである場合、ls -Aは、rootでない場合とは正反対になります-そして、私は信じられないほどの何かを構成することはできません愚か)。
実際、直接の質問を完全に回避したいと思うかもしれません。通常、人々はディレクトリが空であるかどうかを知りたいのです。なぜなら、そこにあるファイルに関係する何かをしたいからです。大きな質問を見てください。たとえば、これらの検索ベースの例の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:No such file or directory but実際にはそのようなテストが必要ない場合のようなエラーメッセージを避けるために、明示的な空のディレクトリテストが必要であると考えたかもしれません。
質問に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
ブロックのコードは、明らかに、すべてのディレクトリで順番に実行されることに注意してください。これが望ましくない場合は、単純に配列パラメーターを入力して、そのパラメーターを操作できます。
$ 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)
は一致します。ディレクトリORは空ではありません。したがって、たとえば、(^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)
glob修飾子を使用して、これらのエラーメッセージを抑制する必要があります。
$ mkdir Y
$ touch Y/.f
$ for i in Y(N/^F) ; do echo $i ; done ; echo "finished"
finished
したがって、空でないディレクトリには(N/^F)
修飾子が必要です。これは、「障害について警告しないでください、ディレクトリがいっぱいではありません」と読むことができます。
同様に、空のディレクトリには、(NF)
修飾子が必要です。これは、同様に次のように読み取ることができます。「失敗について警告しないでください、完全なディレクトリ」。
Olibreの答えからヒント(またはいくつか)を取得すると、Bash関数が好きです。
function isEmptyDir {
[ -d $1 -a -n "$( find $1 -Prune -empty 2>/dev/null )" ]
}
サブシェルを1つ作成しますが、想像できる限りO(1)ソリューションに近く、名前を付けると読みやすくなります。その後、私は書くことができます
if isEmptyDir somedir
then
echo somedir is an empty directory
else
echo somedir does not exist, is not a dir, is unreadable, or is not empty
fi
O(1)に関しては、異常なケースがあります。大きなディレクトリで最後のエントリ以外のすべてまたはすべてが削除されている場合、「find」はすべてを読み取って空かどうかを判断する必要があります。予想されるパフォーマンスはO(1)であると考えていますが、最悪の場合はディレクトリサイズが線形になります。私はこれを測定していません。
ブルーノの答え の小さなバリエーション:
files=$(ls -1 /some/dir| wc -l)
if [ $files -gt 0 ]
then
echo "Contains files"
else
echo "Empty"
fi
わたしにはできる
if ls /some/dir/* >/dev/null 2>&1 ; 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
いくつかの回避策があれば、ディレクトリにファイルがあるかどうかを調べる簡単な方法を見つけることができました。これは、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
これまでのところ、grepを使用した答えは見たことがありませんが、これは単純な答えを与えると思います(奇妙なシンボルはあまり多くありません!)。 bourne Shellを使用してディレクトリにファイルが存在するかどうかを確認する方法は次のとおりです。
これは、ディレクトリ内のファイルの数を返します。
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を開始して、ディレクトリ内のすべてのファイルを検索します。 findの戻り値がnullかどうかを確認します。検索のデータをエコーする
#!/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
bashを使用した簡単な答え:
if [[ $(ls /some/dir/) ]]; then echo "huzzah"; fi;
プルーンのものと最後の答えを混ぜて、私は
find "$some_dir" -Prune -empty -type d | read && echo empty || echo "not empty"
スペースを含むパスでも機能します