2つ以上のファイルがあるディレクトリ


11

現在のディレクトリのサブディレクトリ(つまり、サブディレクトリ)を見つけたいのですが、2つ以上の通常のファイルが含まれています。

2つ未満のファイルを含むディレクトリ、サブディレクトリのみを含むディレクトリには興味がありません。

回答:


12

これは、GNU findとに基づく完全に異なるアプローチですuniq。これは、検出された各ディレクトリのファイルをカウントするシェルコマンドの実行に基づく回答よりもはるかに高速で、CPUフレンドリーです。

find . -type f -printf '%h\n' | sort | uniq -d

このfindコマンドは、階層内のすべてのファイルのディレクトリを印刷し、uniq少なくとも2回表示されるディレクトリのみを表示します。


2
の出力を解析しないでくださいfind。この場合、GNU findは現在のロケール(Cロケールの "ä"など)で印刷できない文字を含むディレクトリの名前を壊すためです。unix.stackexchange.com/questions/321697/…
クサラナンダ

4
@Kusalananda、出力がttyに送られないときではありません。ここでは、唯一の問題は、あなたが使用して修正することができ、改行文字、である-printf '%h\0' | sort -z | uniq -zd | xargs -r0 ...
ステファンChazelas

6
find . -type d \
    -exec sh -c 'c=0; for n in "$1"/*; do [ -f "$n" ] && [ ! -h "$n" ] && c=$(( c + 1 )); done; [ "$c" -ge 2 ]' sh {} ';' \
    -print

これにより、現在のディレクトリ内またはその下のすべての名前が検索され、ディレクトリの名前ではないすべての名前が除外されます。

残りのディレクトリ名は、この短いスクリプトに付けられます。

c=0
for n in "$1"/*; do
    [ -f "$n" ] && [ ! -h "$n" ] && c=$(( c + 1 ))
done

[ "$c" -ge 2 ]

このスクリプトは、最初のコマンドライン引数(からfind)として指定されたディレクトリ内の(シンボリックリンクをスキップする)通常のファイルの数をカウントします。スクリプトの最後のコマンドは、カウントが2以上かどうかを確認するテストです。このテストの結果は、スクリプトの戻り値(終了ステータス)です。

テストが成功した場合は、-print原因となるfindディレクトリへのパスをプリントアウトします。

隠しファイル(名前がドットで始まるファイル)も考慮するには、sh -cスクリプトを次のように変更します。

for n in "$1"/*; do

for n in "$1"/* "$1"/.*; do

テスト:

$ tree
.
`-- test
    |-- a
    |-- dir1
    |   |-- a
    |   |-- b
    |   `-- c
    `-- dir2
        |-- dira
        |-- dirb
        |   |-- file-1
        |   `-- file-2
        `-- dirc

6 directories, 6 files

$ find . -type d -exec sh -c 'c=0; for n in "$1"/*; do [ -f "$n" ] && [ ! -h "$n" ] && c=$(( c + 1 )); done; [ "$c" -ge 2 ]' sh {} ';' -print
./test/dir1
./test/dir2/dirb

ソリューションは、ドットで始まる名前のファイルをカウントしません。また、ファイルを含まないディレクトリでのエラーメッセージを回避するために、c = 0を初期化する必要があります。
xhienne

@xhienne私は隠しファイルを検討し、それについてのメモを追加します。[ "" -ge 2 ]有効なテストであるため、ディレクトリに通常のファイルがなければエラーはありません。
クサラナナンダ

「有効」の定義方法がわからない。POSIXでは、arg1は整数値である必要があります。dashbash --posixおよびtestすべてがエラーメッセージを表示し、2で終了します(つまり、「エラーが発生しました」)
xhienne

@xhienneああ、私はkshとして実行されているシステムでテストしていましたsh。すぐに修正されます。私をつついてくれてありがとう!:-)
クサラナンダ

また、[ -f ... ]シンボリックリンクを逆参照します。質問では、通常のファイルのみをカウントするように指定されているため、テストを追加してそれらを排除する必要があります。
xhienne

6

SUに関するGillesの回答の助けを借りてと、ここで何が必要か、その逆といくつかの変更、。

find . -type d -exec sh -c 'set -- "$1"/*;X=0; 
    for args; do [ -f "$args" ] && X=$((X+1)) ;done; [ "$X" -gt 1 ] ' _ {} \; -print

ディレクトリツリー。

.
├── test
│   ├── dir1
│   │   ├── a
│   │   ├── b
│   │   └── c
│   ├── dir2
│   │   ├── dira
│   │   │   └── a file\012with\012multiple\012line
│   │   ├── dirb
│   │   │   ├── file-1
│   │   │   └── file-2
│   │   └── dirc
│   ├── diraa
│   ├── dirbb
│   ├── dircc
│   └── x
│   └── x1
│   └── x2
└── test2
    ├── dir3
    └── dir4

結果:

./test
./test/dir1
./test/dir2/dirb

私も最初はこれを持っていましたが、複数のサブディレクトリファイルを含むディレクトリに問題があります。また、サブディレクトリのみを含むディレクトリも除外されません。
クサラナンダ

それは本当にそれを解決しません。それは私のテスト設定でtestdir2ディレクトリの両方を見つけます(私の答えを参照してください)。
クサラナナンダ

しかし、あなたの例のための作品は、追加test/x1test/x2同様のファイルとして... $1$2のディレクトリとなりtest、およびディレクトリを見逃すことになります。
クサラナナンダ

@Kusalanandaあなたが答えたもの以外は見つけられなかったので、コマンドの一部を変更して自分のコマンドの完全な複製にならないようにしました(あなたのように隠しファイルを除外しませんでした)。
αғsнιη

1
何の心配もありません:-)
Kusalananda

3

別のfind+ wcアプローチ:

find path/currdir -maxdepth 1 -type d ! -empty ! -path "path/currdir" \
-exec sh -c 'count=$(find "$1" -maxdepth 1 -type f | wc -l); [ $count -ge 2 ]' _ {} \; -print

  • path/currdir -現在のディレクトリへのパス

  • -maxdepth 1- 直接の子サブフォルダーのみを検討する

  • ! -empty -空のサブフォルダーを無視

  • ! -path "path/currdir" -現在のディレクトリパスを無視する

  • count=$(find "$1" -maxdepth 1 -type f | wc -l)- count見つかった各サブフォルダのファイル数が割り当てられます

  • [ $count -ge 2 ] ... -print -2つ以上の通常のファイルを含むサブフォルダー名/パスを印刷する

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.