特定のファイルのみを含むディレクトリを見つける方法

特定のファイルのみを含むディレクトリを見つける方法

役に立たないファイル(たとえば、、、、、など)を含むいくつかのディレクトリがあります*.tmpdesktop.iniThumbs.db.picasa.ini

すべてのドライブを検索して一部のファイルのみを含むディレクトリを見つけるにはどうすればよいですか?

答え1

、および/または以外の名前がない*.tmpすべてのdesktop.iniディレクトリThumbs.dbを見つけるには、次の手順を実行します.picasa.ini

find . -type d -exec bash -O dotglob -c '
    for dirpath do
        ok=true
        seen_files=false
        set -- "$dirpath"/*
        for name do
            [ -d "$name" ] && continue  # skip dirs
            seen_files=true
            case "${name##*/}" in
                *.tmp|desktop.ini|Thumbs.db|.picasa.ini) ;; # do nothing
                *) ok=false; break
            esac
        done

        "$seen_files" && "$ok" && printf "%s\n" "$dirpath"
    done' bash {} +

findこれは、現在のディレクトリの下(含まれている)のディレクトリを見つけてシェルスクリプトに渡すために使用されます。

シェルスクリプトは指定されたディレクトリパスを繰り返し、各ディレクトリパスに対して*その中で展開されます(隠し名前をキャプチャするようにdotglobシェルオプションを設定します)。bash

次に、結果の名前のリストを繰り返して、検索したい特定のパターンと名前と一致させます(ディレクトリを無視)。もし見つけたらその他名前がリストと一致しない場合(from has was)okに設定され、内部ループから外れます。falsetrue

次のタイプを除くすべてのタイプのファイルを見ると、このseen_files変数は次のようになります。true目次(またはディレクトリへのシンボリックリンク)。この変数は、他のサブディレクトリのみを含むサブディレクトリを報告するのを防ぐのに役立ちます。

$seen_files次に、and $oktrueまたは)を実行してfalse両方の場合、trueそのディレクトリに少なくとも1つの一般的なファイルが含まれていることを意味します。リスト内のファイル名のみを含める、ディレクトリのパス名を印刷します。

変える

set -- "$dirpath"/*
for name do

あなたは明らかにこれを行うことができます

for name in "$dirpath"/*; do

代わりに。

テスト:

$ tree
.
`-- dir
    |-- Thumbs.db
    `-- dir
        |-- file.tmp
        `-- something

2 directories, 3 files

findここでコマンドが実行され、出力が生成されます...)

./dir

つまり、ディレクトリ./dirにはリストの名前(ディレクトリを無視)だけが含まれ、./dir/dir他のコンテンツも含まれます。

[ -d "$name" ] && continueコードから削除すると、リスト()にない名前が./dir含まれているため、ディレクトリが見つかりません。dir

答え2

find、xargs、ls、sed、wc、および awk コマンドの組み合わせを使用すると機能します。

find . -type f \( -iname "desktop.ini" -o -name "thumb.db" \)  -printf %h\\0 | xargs -0 -I "{}" sh -c 'printf "{}\t"; ls -l "{}" | sed -n "1!p" | wc -l' | awk '$2 == "1" {print $0}'

説明する:

  • find .現在のディレクトリで検索
  • -type fファイルのみ検索
  • \( -iname "desktop.ini" -o -name "thumb.db" \)ここで、ファイル名は「desktop.ini」または「thumb.db」で、大文字と小文字を区別しません。
  • printf %h\\0ファイル名+ASCII NULの先頭ディレクトリを印刷します。
  • xargs -0 -I "{}" sh -c 'printf "{}\t"; ls -l "{}"出力ディレクトリを印刷し、ls -l各ディレクトリで実行
  • sed -n "1!p" | wc -l'ファイル全体とディレクトリを含む最初の行を除き、行数を計算しますls -l
  • awk '$2 == "1" {print $0}'数が「1」に等しい場合は、その行を印刷します。

答え3

ファイルまたはフォルダを名前で指定することをお勧めします。たとえば、次のようになります。

find ${HOME} -type f -iname thumbs.db -print0 | xargs -0 --no-run-if-empty rm

() "thumbs.db"-type fという名前のすべてのファイルを見つけて()削除します()。-inameiinamerm

次のファイル名パターンを使用できます。

find ${HOME} -type f -iname '*.tmp' -print0 | xargs -0 --no-run-if-empty rm

警告する:ご入力いただいた内容にご注意ください。リクエストなしで削除できます。

定期的にバックアップしてください。クリーンアッププロセスを開始する前に良い時間になることができます!

何を期待するかを知りたい場合は、rm作業を実行する前にファイルのリストを見てください。たとえば、次のようになります。

find ${HOME} -type f -iname thumbs.db -print0 | xargs -0 --no-run-if-empty ls -l

答え4

GNUfindとGNUを使用すると、すべてのファイルを報告して一致させるawkことができます。findawk

find . -depth -type d -printf '%p/\0' -o -printf '%p\0' |
  gawk -F/ -v OFS=/ -v RS='\0' -v IGNORECASE=1 '
    /\/$/ {
     NF--
     if (good[$0] == 0 && bad[$0] > 0) print
     next
    }
    {
      name = $NF
      NF--
      if (name ~ /^(.*\.tmp|desktop\.ini|Thumbs\.db|\.picasa\.ini)$/)
        bad[$0]++
      else
        good[$0]++
    }'

空のディレクトリを含めるには、削除してください&& bad[$0] > 0。大文字と小文字を区別するには、削除してください-v IGNORECASE=1

関連情報