web-dev-qa-db-ja.com

ディレクトリにファイルが含まれているかどうかをシェルスクリプトから確認する

シェルスクリプトから、ディレクトリにファイルが含まれているかどうかを確認するにはどうすればよいですか?

これに似たもの

if [ -e /some/dir/* ]; then echo "huzzah"; fi;

ただし、ディレクトリに1つまたは複数のファイルが含まれている場合は機能します(上記のファイルは正確に0または1つのファイルでのみ機能します)。

104
ionn

これまでのソリューションでは、lsを使用しています。これがすべてbashソリューションです。

#!/bin/bash
shopt -s nullglob dotglob     # To include hidden files
files=(/some/dir/*)
if [ ${#files[@]} -gt 0 ]; then echo "huzzah"; fi
62
Bruno De Fraine

3つのベストトリック


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 -Prunefind -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

この最後のコードはほとんどの場合に機能しますが、悪意のあるパスがコマンドを表現する可能性があることに注意してください...

128
olibre

以下はどうですか:

if find /some/dir/ -maxdepth 0 -empty | read v; then echo "Empty dir"; fi

この方法では、ディレクトリの内容の完全なリストを生成する必要はありません。 readは、出力を破棄し、何かが読み取られた場合にのみ式をtrueに評価します(つまり、findによって/some/dir/が空であることが検出された場合)。

48
mweerden

試してください:

if [ ! -z `ls /some/dir/*` ]; then echo "huzzah"; fi
20
Greg Hewgill

たくさんのファイルがあるディレクトリには注意してください! lsコマンドの評価には時間がかかる場合があります。

IMOの最良の解決策は、

find /some/dir/ -maxdepth 0 -empty
14
Gravstar
# 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
}
14
gr8can8dian
DIR="/some/dir"
if [ "$(ls -A $DIR)" ]; then
     echo 'There is something alive in here'
fi
9
Andrew Taylor

これの出力を比較できますか?

 ls -A /some/dir | wc -l
5
DGM
#ディレクトリに非表示でないファイルが含まれているかどうかを確認します。
#
#使用法: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/*"が割り当てられます。そのファイルが存在する場合のみ、関数は「空でない」を返します
  • この関数は、すべてのPOSIX実装で機能します。ただし、Solarisの/ bin/shはそのカテゴリに該当しないことに注意してください。 test実装は-eフラグをサポートしていません。
4
Roland Illig

これにより、ディレクトリが空であるか、空でない場合、含まれているファイルの数がわかります。

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
3
Daishi

これは非常に遅い応答かもしれませんが、ここに機能する解決策があります。この行はファイルの存在のみを認識します!ディレクトリが存在する場合、誤検知は発生しません。

if find /path/to/check/* -maxdepth 0 -type f | read
  then echo "Files Exist"
fi
2
bitstreamer
dir_is_empty() {
   [ "${1##*/}" = "*" ]
}

if dir_is_empty /some/dir/* ; then
   echo "huzzah"
fi

*という名前のファイルが/any/dir/you/checkにない場合、bashdashposhbusybox 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が空の場合の引数と検索出力の違い、および末尾の改行(ただし、これは扱いやすいはずです)、悲しいことに私のbusyboxshfind -> ddのおそらくバグを示しています出力がランダムに切り捨てられたパイプ(catを使用した場合、出力は常に同じで、引数ddを持つcountのようです)。

1
Alex

空のディレクトリに関する基本的なガイド が言及されていないことに驚いています。このガイド、および実際にすべての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実際にはそのようなテストが必要ない場合のようなエラーメッセージを避けるために、明示的な空のディレクトリテストが必要であると考えたかもしれません。

1
bishop

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ブロックのコードは、明らかに、すべてのディレクトリで順番に実行されることに注意してください。これが望ましくない場合は、単純に配列パラメーターを入力して、そのパラメーターを操作できます。

$ 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)修飾子が必要です。これは、同様に次のように読み取ることができます。「失敗について警告しないでください、完全なディレクトリ」。

1
Zorawar

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)であると考えていますが、最悪の場合はディレクトリサイズが線形になります。私はこれを測定していません。

1
ForDummies

ブルーノの答え の小さなバリエーション:

files=$(ls -1 /some/dir| wc -l)
if [ $files -gt 0 ] 
then
    echo "Contains files"
else
    echo "Empty"
fi

わたしにはできる

1
loockass
if ls /some/dir/* >/dev/null 2>&1 ; then echo "huzzah"; fi;
0
Toby

私は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
0
fedorqui

いくつかの回避策があれば、ディレクトリにファイルがあるかどうかを調べる簡単な方法を見つけることができました。これは、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
0
chanaka777

これまでのところ、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は選択した変数です。

0
Jecht Tyre

コマンド検索で試してください。ハードコーディングされたディレクトリまたは引数として指定します。次に、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
0
GiannakopoulosJ

bashを使用した簡単な答え:

if [[ $(ls /some/dir/) ]]; then echo "huzzah"; fi;
0

プルーンのものと最後の答えを混ぜて、私は

find "$some_dir" -Prune -empty -type d | read && echo empty || echo "not empty"

スペースを含むパスでも機能します

0
Laurent G