在 Linux 或 Windows 上,如何找到该目录中唯一的所有 mp3 的路径?

在 Linux 或 Windows 上,如何找到该目录中唯一的所有 mp3 的路径?

我有一个音乐文件夹,其内容如下:

音乐
    —艺术家A
        -歌曲1.mp3
        -专辑mA
            -歌曲2.mp3
            -歌曲2.m4a
        —专辑B
            -歌曲1.mp3
            -歌曲2.mp3
            -歌曲3.mp3
        —专辑C
            -歌曲1.mp3
            -歌曲1.jpg
            -某些文件夹1
                -歌曲1.mp3
    —艺术家B
        -歌曲1.mp3
    —艺术家C
        -歌曲1.mp3
        -歌曲2.mp3
        -歌曲3.mp3
        -某些文件夹2
            -歌曲1.jpg
            -歌曲2.jpg
        -某些文件夹3


我正在寻找这样的输出:

艺术家 A/歌曲 1.mp3
艺术家 A/专辑 A/歌曲 2.mp3
艺术家 A/专辑 C/歌曲 1.mp3
艺术家 A/专辑 C/SomeFolder1/歌曲 1.mp3
艺术家B/歌曲1.mp3



因此,我不想要只有一个文件的目录,我想要只有一个 mp3 的目录 - 不管子目录或其他文件。我也不想要空目录,或者包含多个 mp3 的目录。

我并不反对 Linux 的 shell 脚本。但是,我不想在任何一个操作系统上编译程序。

我已经尝试过: find . -type d -exec sh -c 'set -- "$0"/*.mp3; [ $# -le 1 ]' {} \; -print

但是这给了我这个输出:


./艺术家B
./艺术家A
./艺术家 A/专辑 A
./艺术家 A/专辑 C
./艺术家A/专辑C/SomeFolder1
./ArtistC/SomeFolder2
./ArtistC/SomeFolder3

虽然很接近,但不是我想要的。有两个空文件夹,没有文件名。

答案1

乍一看,第一个命令报告空文件夹(没有*.mp3文件的文件夹)的原因在于您说的-le 1是 而不是-eq 1。这看起来会报告包含一个或更少 MP3 文件的目录。但是更改-le 1-eq 1不起作用。事实证明,问题是,在包含 ≥ 一个 MP3 文件的目录中, directory_name/*.mp3会为您提供 MP3 文件名列表,但是,在没有文件的目录中,它仍然保持为directory_name/*.mp3。可以通过告诉 shell 不匹配任何文件的通配符应该从命令行中消失来解决这个问题:

查找 .-type d-exec
        響 -c 'shopt -s nullglob;设置——“$0”/*.mp3;[$#-eq 1]'{}\;-print

(全部输入为一行)结果

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

但是您让 shell 统计文件数量,并要求find打印 – 并且find只查看目录。为什么不让 shell 打印它看到的文件名呢?

查找 .-type d-exec
        sh -c'shopt-s nullglob;设置——“$0”/*.mp3; [$#-eq 1]&& 回显“$1”‘{} \;

(即,如果有一个文件,echo第一个文件的名称($1))将会提供您想要的内容。

答案2

对于使用 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} 

提取每个目录中与文件掩码匹配的一个文件的全名

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

答案3

我确信有人有更好的方法来实现这一点,但是这个 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

结果是一样的,但它只会检查每个文件夹一次,这可以节省大量时间。awk 命令会删除任何重复的文件夹名称。

另一个注意事项是,Linux 上的文件区分大小写,因此这将完全忽略任何.MP3.Mp3文件。如果您希望它匹配这些文件,请将所有 3 个实例更改mp3[mM][pP]3

答案4

以下是答案:

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

相关内容