Linux 按艺术家、唱片集、歌曲名称将mp3文件从一个目录移动到不同的目录

Linux 按艺术家、唱片集、歌曲名称将mp3文件从一个目录移动到不同的目录,linux,bash,Linux,Bash,我在一个文件夹中备份了我所有的MP3文件 是否有bash命令自动移动他们自己的乐队专辑标题目录中的所有文件 如图所示,dash前面的第一个单词是艺术家姓名,然后是专辑标题,然后是歌曲名称 示例:艺术家或乐队-专辑标题-song.mp3的名称 因此,最终,文件将处于以下层次结构中 Artist or band1/ album title1/ name of song.mp3 album title2/

我在一个文件夹中备份了我所有的MP3文件

是否有bash命令自动移动他们自己的乐队专辑标题目录中的所有文件

如图所示,dash前面的第一个单词是艺术家姓名,然后是专辑标题,然后是歌曲名称

示例:艺术家或乐队-专辑标题-song.mp3的名称

因此,最终,文件将处于以下层次结构中

Artist or band1/    
        album title1/
                name of song.mp3
        album title2/
                name of song.mp3    

Artist or band2/
        album title1/
                name of song.mp3

等等。

我不知道有什么命令可以直接执行此操作,但下面是我如何使用Perl解决此问题的:

perl -MFile::Path -we 'for my $file (glob "*.mp3") { my ($artist, $album, $title) = split / - /, $file, 3; mkpath "$artist/$album"; my $new = "$artist/$album/$title"; rename $file, $new or warn "$file -> $new: $!\n"; }'
或者更具可读性:

perl -MFile::Path -we '
    for my $file (glob "*.mp3") {
        my ($artist, $album, $title) = split / - /, $file, 3;
        mkpath "$artist/$album";
        my $new = "$artist/$album/$title";
        rename $file, $new or die "$file -> $new: $!\n";
    }'

我不知道有什么命令可以直接执行此操作,但下面是我如何使用Perl解决此问题的:

perl -MFile::Path -we 'for my $file (glob "*.mp3") { my ($artist, $album, $title) = split / - /, $file, 3; mkpath "$artist/$album"; my $new = "$artist/$album/$title"; rename $file, $new or warn "$file -> $new: $!\n"; }'
或者更具可读性:

perl -MFile::Path -we '
    for my $file (glob "*.mp3") {
        my ($artist, $album, $title) = split / - /, $file, 3;
        mkpath "$artist/$album";
        my $new = "$artist/$album/$title";
        rename $file, $new or die "$file -> $new: $!\n";
    }'

在Bash中,我将按如下方式执行:

#!/bin/bash

# Set field separator to dash
IFS=-

# Loop over mp3 files
for song in *.mp3; do

    # Read long name into dash separated array
    read -a songinfo <<< "$song"

    # Remove trailing space from band name
    band=${songinfo[0]% }

    # Remove trailing and leading space from album name
    album=${songinfo[1]% }
    album=${album# }

    # Remove leading space from song title
    title=${songinfo[2]# }

    # Make band/album directory, don't complain if they exist already
    mkdir --parents "$band/$album"

    # Move and rename song
    mv "$song" "$band/$album/$title"
done
这会更改IFS变量,但由于它将在子进程中运行,因此我没有将其重置为原始值


由于参数扩展以删除空格,它有点长,当然,如果乐队/专辑/歌曲名称之间以外的地方出现破折号,它就会中断。对于在其他地方也可以使用破折号的Bash解决方案,请参见。

我将在Bash中执行以下操作:

#!/bin/bash

# Set field separator to dash
IFS=-

# Loop over mp3 files
for song in *.mp3; do

    # Read long name into dash separated array
    read -a songinfo <<< "$song"

    # Remove trailing space from band name
    band=${songinfo[0]% }

    # Remove trailing and leading space from album name
    album=${songinfo[1]% }
    album=${album# }

    # Remove leading space from song title
    title=${songinfo[2]# }

    # Make band/album directory, don't complain if they exist already
    mkdir --parents "$band/$album"

    # Move and rename song
    mv "$song" "$band/$album/$title"
done
这会更改IFS变量,但由于它将在子进程中运行,因此我没有将其重置为原始值


由于参数扩展以删除空格,它有点长,当然,如果乐队/专辑/歌曲名称之间以外的地方出现破折号,它就会中断。对于在其他地方也可以使用破折号的Bash解决方案,请参见。

Bash解决方案,以同时考虑破折号也存在于所有时间的四分卫中


bash的解决方案,也要考虑到dash-也一直是四分卫中的一员

这是最好的解决办法

这里是一个纯Bash实现,除了调用外部实用程序mkdir和mv之外,它在避免误报方面也很健壮:

for fname in *.mp3; do
  IFS=/ read -r artist album song <<<"${fname// - //}"
  song="${song//// - }"
  mkdir -p "$artist/$album"
  mv "$fname" "$artist/$album/$song"
done
${fname/-/}使用Bash参数扩展将所有//-序列替换为/a/char。每个

这种替换的原因是Bash的令牌拆分机制只能拆分多个单个字符中的一个。 选择辅助分隔符/是因为它保证不包含在输入文件名中。 结果通过一个字符串输入读取是最好的解决方案

这里是一个纯Bash实现,除了调用外部实用程序mkdir和mv之外,它在避免误报方面也很健壮:

for fname in *.mp3; do
  IFS=/ read -r artist album song <<<"${fname// - //}"
  song="${song//// - }"
  mkdir -p "$artist/$album"
  mv "$fname" "$artist/$album/$song"
done
${fname/-/}使用Bash参数扩展将所有//-序列替换为/a/char。每个

这种替换的原因是Bash的令牌拆分机制只能拆分多个单个字符中的一个。 选择辅助分隔符/是因为它保证不包含在输入文件名中。
结果通过一个here字符串输入读取,我也测试了它,它工作了。因为我最初的问题是要求一个BASH解决方案,所以我将这个问题标记为解决方案。perl的答案也很有效。@BenjaminW.-这个解决方案很好用,只是它确实会给所有时间的四分卫歌曲带来问题。我也测试了这个,它很有效。因为我最初的问题是要求一个BASH解决方案,所以我将这个问题标记为解决方案。perl的答案也很有效。@BenjaminW.-该解决方案运行良好,但它确实会为所有时间的四分卫歌曲产生问题。除了比纯Bash解决方案更短、可能更快之外,此解决方案的显著优点是仅通过-进行拆分,并确保拆分结果不超过3个令牌。除了比纯Bash解决方案更短、可能更快之外,此解决方案的显著优点是只按-进行拆分,并确保拆分结果不超过3个令牌。这也起到了作用。另外,.mp3文件的名称没有更改。@Eric-也添加了该功能。希望它能有所帮助:很好,但您的解决方案效率很低,因为在每个循环迭代中创建了多个子shell,每个子shell都调用awk。Bash循环天生就很慢,如果在每次迭代中调用外部实用程序,那么每次迭代都要调用mkdir-p和mv,这是无法避免的,但是有一些方法可以避免子shell和awk调用。这也很有效。另外,.mp3文件的名称没有更改。@Eric-也添加了该功能。希望它能有所帮助:很好,但您的解决方案效率很低,因为在每个循环迭代中创建了多个子shell,每个子shell都调用awk。Bash循环天生就很慢,如果在每次迭代中调用外部实用程序,那么在这里无法避免每次迭代对mkdir-p和mv的调用,但是有一些方法可以避免子shell和awk调用。