web-dev-qa-db-ja.com

LinuxまたはWindowsで、そのディレクトリ内の唯一のmp3であるすべてのmp3のパスを見つけるにはどうすればよいですか?

音楽フォルダがあり、コンテンツは次のようになります。

音楽
-ArtistA 
-Song1.mp3 
-AlbumA 
 _ ._ a _ ._ a _ _ _ _ _ _ 。] -AlbumB 
 -Song1.mp3 
 -Song2.mp3 
 -Song3.mp3 
 -AlbumC 
 -Song1.mp3 
-Song1.jpg 
-SomeFolder1 
-Song1.mp3 
-ong1.mp3 
-[._] _] -Song1.mp3 
-Song2.mp3 
-Song3.mp3 
-SomeFolder2 
-ong1 
 _ _ ._ _ 。]-SomeFolder3 


次のような出力を探しています:

 ArtistA/Song1.mp3 
 ArtistA/AlbumA/Song2.mp3 
 ArtistA/AlbumC/Song1.mp3 
 ArtistA/AlbumC/SomeFolder1/Song1.mp3 
 ArtistB/Song1.mp3 



したがって、ファイルが1つしかないディレクトリは必要ありません。サブディレクトリや他のファイルに関係なく、mp3が1つしかないディレクトリが必要です。また、空のディレクトリ、または複数のmp3を含むディレクトリも必要ありません。

私はLinux用のシェルスクリプトに反対していません。ただし、どちらのOSでもプログラムをコンパイルしたくありません。

私が試してみました: find . -type d -exec sh -c 'set -- "$0"/*.mp3; [ $# -le 1 ]' {} \; -print

しかし、それは私にこの出力を与えます:

。
。/ArtistB 
 ./ ArtistsA 
 ./ ArtistA/AlbumA 
。/ArtistA/AlbumC 
。/ArtistA /AlbumC/SomeFolder1
./ArtistC/SomeFolder2
./ArtistC/SomeFolder3

これは近いですが、私が望むものとは異なります。空のフォルダが2つあり、ファイル名はありません。

3
RalphyZ

一見したところ、最初のコマンドが空のフォルダー(*.mp3ファイルがないフォルダー)を報告している理由は、-le 1ではなく-eq 1と言っているためです。これは、MP3ファイルが1つ以下のディレクトリを報告するようです。ただし、-le 1-eq 1に変更しても機能しません。問題は、MP3ファイルが1つ以上あるディレクトリでは、directory_name/*.mp3がMP3ファイル名のリストを取得することですが、MP3ファイル名がないディレクトリでは、文字通りdirectory_name/*.mp3のままです。これは、ファイルに一致しないワイルドカードをコマンドラインから削除するようにシェルに指示することで修正できます。

見つける。 -type d -exec 
 sh -c 'shopt -s nullglob; セット-"$ 0"/*。mp3; [$#-eq 1] '{} \; -印刷

(すべて1行で入力)

./ArtistA
./ArtistA/AlbumA
./ArtistA/AlbumC
./ArtistA/AlbumC/SomeFolder1
./ArtistB

しかし、シェルがファイルをカウントしていて、findに印刷を依頼しているのですが、findはディレクトリのみを調べています。シェルに表示されたファイル名を出力させないのはなぜですか?

見つける。 -type d -exec 
 sh -c'shopt -s nullglob;セット-"$ 0"/*。mp3; [$#-eq 1] && echo "$ 1"'{} \;

(つまり、ファイルが1つある場合、echo最初のファイルの名前($1))は、必要なものを提供します。

PowerShellを使用するWindowsの場合、既にフォルダーC:\ YOUR_PATH:にいると仮定します。

PS C:\YOUR_PATH> (Get-ChildItem -recurse | Where-Object {$_.name -match ".mp3"}) | Group-Object -Property Directory | Where-Object {$_.Count -eq 1} | ForEach-Object { (Get-ChildItem $_.Name -Filter "*.mp3").FullName}

出力:

C:\YOUR_PATH\ArtistA\Song1.mp3
C:\YOUR_PATH\ArtistA\AlbumA\Song2.mp3
C:\YOUR_PATH\ArtistA\AlbumC\Song1.mp3
C:\YOUR_PATH\ArtistA\AlbumC\SomeFolder1/Song1.mp3
C:\YOUR_PATH\ArtistB\Song1.mp3

パイプされたコマンドの分解:

現在のディレクトリの下にあるすべてのファイルとフォルダを取得します

Get-ChildItem -recurse 

マスクに基づいてファイルのみを照合します

Where-Object {$_.name -match ".mp3"})

ディレクトリプロパティに基づいてグループ化を実行します

Group-Object -Property Directory 

1項目のディレクトリのみを選択してください

Where-Object {$_.Count -eq 1} 

各ディレクトリのファイルマスクに一致する1つのファイルのフルネームを抽出します

ForEach-Object { (Get-ChildItem $_.Name -Filter "*.mp3").FullName} 
4
nvuono

誰かがそれを行うより良い方法を持っていると確信していますが、このbashコマンドはLinuxで機能します。

for Folder in $(find . -name "*.mp3" -printf "%h\n")
do
    [[ $(ls -l $Folder/*.mp3 | wc -l) -eq "1" ]] && ls $Folder/*.mp3
done

このスクリプトは、すべての.mp3ファイルのフォルダーでテストを実行し、同じファイルで一致するたびにそれ自体を繰り返します。たとえば、Music/ArtistA/AlbumBを3回チェックします。持っているmp3ファイルの数によっては、これには長い時間がかかる場合があります(かなり巨大なライブラリが必要になります)。

もしそうなら、あなたはそれをもう少し複雑にすることができます:

for Folder in $(find . -name "*.mp3" -printf "%h\n" | awk '!x[$0]++')
    do
        [[ $(ls -l $Folder/*.mp3 | wc -l) -eq "1" ]] && ls $Folder/*.mp3
    done

結果は同じですが、各フォルダーを1回だけチェックするため、時間を大幅に節約できます。 awkコマンドは、重複するフォルダー名をすべて削除します。

Linuxではファイルで大文字と小文字が区別されるため、.MP3または.Mp3filesは完全に無視されます。それらと一致させたい場合は、mp3の3つのインスタンスすべてを[mM][pP]3に変更します。

1
Omnipresence

答えは次のとおりです。

find Music -name "*.mp3" -exec dirname {} \; |
    sort |
    uniq -c |
        while read count parent
        do
            if [[ $count -eq 1 ]]
            then
                echo "$parent"/*.mp3
            fi
        done
0
bonh