ファイルが含まれていないディレクトリを見つける


58

はい、音楽を整理しています。私はすべてを次のマントラで美しく配置しました:/Artist/Album/Track - Artist - Title.ext存在する場合、カバーはにあり/Artist/Album/cover.(jpg|png)ます。

すべての第2レベルのディレクトリをスキャンして、カバーのないディレクトリを探します。2番目のレベルで/Britney Spears/は、cover.jpgがない場合は気にしませんが、カバー/Britney Spears/In The Zone/がない場合は気にします。

カバーのダウンロードについては心配しないでください(明日は楽しいプロジェクトです)find


ただインストール欠けているカバーのダウンロードに興味があります誰のためのlaunchpad.net/coverlovinをし、と答える@phoibosに-printを置き換える「-exec ./coverlovin.py {} \;」を
Dror Cohen 14

回答:


81

ケース1:検索する正確なファイル名を知っている

findwith test -e your_fileを使用して、ファイルが存在するかどうかを確認します。たとえばcover.jpg、中にないディレクトリを探します:

find base_dir -mindepth 2 -maxdepth 2 -type d '!' -exec test -e "{}/cover.jpg" ';' -print

ただし、大文字と小文字は区別されます。

ケース2:より柔軟にしたい

あなたはケースがわからない、と拡張子はjPg、かもしれないpng...

find base_dir -mindepth 2 -maxdepth 2 -type d '!' -exec sh -c 'ls -1 "{}"|egrep -i -q "^cover\.(jpg|png)$"' ';' -print

説明:

  • sh使用時にはパイピングができないため、ディレクトリごとにシェルを作成する必要がありますfind
  • ls -1 "{}"find現在トラバースしているディレクトリのファイル名のみを出力します
  • egrep(の代わりにgrep)拡張正規表現を使用します。-i検索で大文字と小文字を区別-qせず、出力を省略します
  • "^cover\.(jpg|png)$"は検索パターンです。この例では、たとえばcOver.pngCover.JPGまたはに一致しcover.pngます。.それが一致していることを意味しそうエスケープする必要があります任意の文字を。^ラインの開始をマークし、$その終わり

egrepの他の検索パターンの例

egrep -i -q "^cover\.(jpg|png)$"部品を次のように置き換えます。

  • egrep -i -q "cover\.(jpg|png)$":にも一致cd_cover.pngalbum_cover.JPGます...
  • egrep -q "^cover\.(jpg|png)$":一致しますがcover.png、一致しcover.jpgませんCover.jpg(大文字と小文字の区別はオフになりません)
  • egrep -iq "^(cover|front)\.jpg$":例えばと一致しfront.jpgCover.JPGしかしではありません Cover.PNG

詳細については、正規表現をご覧ください。


絶対に美しい—ケースや異なる拡張子を選択するのは柔軟ではないという問題がある(ワイルドカードを試したが失敗した)。のより良い代替手段があるのだろうかtest
オリ

1
これで検索をネストできますが-exec bash -c '[[ -n $(find "{}" -iname "cover.*") ]]' \;、最適化の点ではかなり不潔です。それは動作しますが。
オリ

ORクエリのtest負荷を渡すことができることがわかりました-o EXPRESSION。たとえばtest -e "{}/cover.jpg" -o -e "{}/cover.png"、完全な検索を実行するよりも優れていますが、大文字と小文字は区別されます。
オリ

このパフォーマンス(前回のコメントごとに2回のテスト)を他の2つのソリューション(comm'd findおよびcomm'd globbing)と比較すると、これがはるかに遅い(それぞれ684ms対40msおよび50ms)
Oli

元のインアンサーソリューションは1秒以上かかり$、dir名(たとえば、Ke $ ha)にある状況で中断します。
オリ

12

シンプルで、蒸散します。以下は、カバー付きのディレクトリのリストを取得し、それをすべての第2レベルのディレクトリのリストと比較します。両方の「ファイル」に表示される行は抑制され、カバーが必要なディレクトリのリストが残ります。

comm -3 \
    <(find ~/Music/ -iname 'cover.*' -printf '%h\n' | sort -u) \
    <(find ~/Music/ -maxdepth 2 -mindepth 2 -type d | sort) \
| sed 's/^.*Music\///'

やったー

ノート:

  • commの引数は次のとおりです。

    • -1 file1に固有の行を抑制します
    • -2 file2に固有の行を抑制します
    • -3 両方のファイルに現れる行を抑制する
  • commファイルのみを使用するため、不自然な<(...)入力メソッドです。これにより、実際の[一時]ファイルを介してコンテンツがパイプされます。

  • commソートされた入力を必要とするか、機能せずfind、順序を保証するものではありません。また、一意である必要があります。最初のfind操作では複数のファイルが検出されるcover.*ため、エントリが重複する可能性があります。sort -uそれらを1つにすばやくフリルします。2番目の検索結果は常に一意になります。

  • dirnameは、sed(など)に頼らずにファイルのディレクトリを取得するための便利なツールです。

  • findそしてcomm、両方の彼らの出力と少し厄介です。最後にsedは物事をきれいにするためにあるので、あなたは残っていArtist/Albumます。これは、あなたにとって望ましい場合とそうでない場合があります。


2
あなたの最初のものfindはおそらくに簡素化できfind ~/Music/ -iname 'cover.*' -printf '%h\n'、の必要を避けdirnameます。しかし、dirname他の場所で便利です。
トム

@Tomに感謝、それはどこでもフォークするよりもずっと速いです(私の音楽ディレクトリで29ms対734ms-両方の「暖かい」発見)
オリ

9

これは、検索よりもグロブで解決する方がはるかに優れています。

$ cd ... # to the directory one level above the album/artist structure

$ echo */*/*.cover   # lists all the covers

$ printf "%s\n" */*/*.cover # lists all the covers, one per line

ここで、この素敵な構造に不要なファイルがないとします。現在のディレクトリにはアーティストのサブディレクトリのみが含まれ、アルバムのサブディレクトリのみが含まれます。その後、次のようなことができます。

$ diff  <(for x in */*/cover.jpg; do echo "$(dirname "$x")" ; done) <(printf "%s\n" */*)

<(...)構文はbashのプロセスの置換である:それはあなたがファイル引数の代わりにコマンドを使用することができます。コマンドの出力をファイルとして扱うことができます。したがって、出力を一時ファイルに保存せずに、2つのプログラムを実行し、それらの差分を取ることができます。diffプログラムは、2つのファイルで作業しているが、実際に、それは2本のパイプから読んでいると考えています。

右の手入力を生成コマンドはdiffprintf "%s\n" */*ちょうどアルバムのディレクトリを示します。左側のコマンドは、*.coverパスを反復処理し、ディレクトリ名を出力します。

テスト走行:

$ find .   # let's see what we have here
.
./a
./a/b
./foo
./foo/bar
./foo/baz
./foo/baz/cover.jpg

$ diff  <(for x in */*/cover.jpg; do echo "$(dirname "$x")" ; done) <(printf "%s\n" */*)
0a1,2
> a/b
> foo/bar

なるほど、a/bfoo/barディレクトリは全くありませんcover.jpg

*一致しない場合はデフォルトでそれ自体に展開するなど、いくつかの破損したケースがあります。これはBashで対処できますset -o nullglob


返信が遅くなって申し訳ありません。それは面白いアイデアですが、カバーはpngとjpbであり、commよりきれいではないでしょうdiffか?
オリ

comm -3 <(printf "%s\n" */*/cover* | sed -r 's/\/[^\/]+$//' | sort -u) <(printf "%s\n" */*)diffの綿毛のない賢明な妥協のようです。ただし、ダブル検索よりも少し遅いです。
オリ

0
ls --color=never */*.txt | sed 's|/.*||' | sort -u -n > withtxt.txt
ls --color=never -d * | sort -u -n > all.txt
diff all.txt withtxt.txt

txtファイルが含まれていないすべてのディレクトリが表示されます。

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