指定されたファイル名のファイルを含まないディレクトリをすべて一覧表示します。

指定されたファイル名のファイルを含まないディレクトリをすべて一覧表示します。

全てのディレクトリをリストするにはどうすればいいでしょうか?ない指定されたファイル名のファイルがありますか?例えば、このツリーが与えられた場合

/
  /a
     README
     file001
     file002
  /b
     README
     file001
  /c
     file003

ディレクトリを一覧表示したいないという名前のファイルがありREADME、この場合はディレクトリ になります/c。どうすればいいでしょうか? たとえば を使用する構文が思いつきませんfind

答え1

引数に埋め込まれた を受け入れるfindGNU のような実装を想定すると、次のようになります。find{}-exec

$ find . -type d \! -exec test -e '{}/README' \; -print

または、問題のある埋め込みなしで:

$ find . -type d ! -exec sh -c 'test -e "$1"/README' sh {} \; -print

ここでは、ディレクトリ 1/1 から 5/5 に README があり、他のディレクトリは空です。

$ tree 
.
|-- 1
|   `-- 1
|       `-- README
|-- 10
|   `-- 10
|-- 2
|   `-- 2
|       `-- README
|-- 3
|   `-- 3
|       `-- README
|-- 4
|   `-- 4
|       `-- README
|-- 5
|   `-- 5
|       `-- README
|-- 6
|   `-- 6
|-- 7
|   `-- 7
|-- 8
|   `-- 8
`-- 9
    `-- 9

ここで、このバージョンのコマンドを実行しますfind

$ find . -type d \! -exec test -e '{}/README' \; -print
.
./10
./10/10
./7
./7/7
./9
./9/9
./6
./6/6
./5
./8
./8/8
./4
./1
./3
./2

参考文献

答え2

は必要ありませんfind。シェルを使用するだけです:

for d in */; do [ -f "$d"README ] || printf '%s\n' "$d"; done
c/

再帰的に行う必要がある場合は、 を使用できます ( の場合bashzshはデフォルトでこれを実行できますが、set -o globstarでは を使用しますksh93)。

shopt -s globstar
for d in **/; do [ -f "$d"README ] || printf '%s\n' "$d"; done

(ドットファイルはデフォルトで除外されることに注意してください)。

答え3

-execオプションを使用してfindファイルをチェックし、チェックに失敗したすべての結果を印刷することができます。

find /path/to/base -mindepth 1 -maxdepth 1 -type d -exec test -e {}/README \; -o -print

答え4

ポータブルでは、次のことができます。

find . -type d -exec sh -c '
  for dir do
    [ -f "$dir/README" ] || printf "%s\n" "$dir"
  done' sh '{}' +

[ -f file ]ファイルが存在する そして通常のファイルであることが確認されます(シンボリックリンクの解決後)。

タイプに関係なく、(そのディレクトリ内のエントリとして) のみが存在することをテストしたい場合は、以下が必要です。ただし、これらのテストを実行するには、ディレクトリに対する検索権限が必要であることに注意してください。次のようなケースを考慮して[ -e file ] || [ -L file ]、いくつかのテストを追加することもできます。[ -x "$dir" ]

find . -type d -exec sh -c '
  for dir do
    if [ -x "$dir" ]; then
      [ -f "$dir/README" ] || printf "%s\n" "$dir"
    else
      printf >&2 "Cannot tell for \"%s\"\n" "$dir"
    fi
  done' sh '{}' +

あるいは、競合状態を回避するには、次のようにしますzsh

find . -type d -exec zsh -c '
  zmodload zsh/system
  for dir do
    ERRNO=0
    if [ ! -f "$dir/README" ]; then
      if [ "$errnos[ERRNO]" = ENOENT ]; then
        printf "%s\n" "$dir"
      else
        syserror -p "ERROR: $dir/README: "
      fi
    fi
  done' zsh '{}' +

参照Bash に通常のファイルが存在しないかどうかを確認するにはどうすればよいですか?SO で。

関連情報