音楽フォルダがあり、コンテンツは次のようになります。
音楽 -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つあり、ファイル名はありません。
一見したところ、最初のコマンドが空のフォルダー(*.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}
誰かがそれを行うより良い方法を持っていると確信していますが、この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
または.Mp3
filesは完全に無視されます。それらと一致させたい場合は、mp3
の3つのインスタンスすべてを[mM][pP]3
に変更します。
答えは次のとおりです。
find Music -name "*.mp3" -exec dirname {} \; |
sort |
uniq -c |
while read count parent
do
if [[ $count -eq 1 ]]
then
echo "$parent"/*.mp3
fi
done