按照艺术家,专辑,歌曲名称将mp3文件从一个目录移动到不同的目录

时间:2016-06-19 00:39:30

标签: linux bash

我在一个文件夹中备份了所有mp3文件。

是否会有一个bash命令来自动移动他们自己的乐队相册标题目录中的所有文件,这些文件将在动态创建?

正如您在图片中看到的那样,破折号之前的第一个单词是艺术家姓名,然后是专辑标题,然后是歌曲的名称。

enter image description here

示例:艺术家或乐队 - 专辑标题 - 歌曲名称.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

等等。

4 个答案:

答案 0 :(得分:3)

我不知道直接执行此操作的命令,但这是我将如何解决此问题(使用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";
    }'

答案 1 :(得分:1)

我会在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解决方案,请参阅mklement0's answer

答案 2 :(得分:1)

melpomene's robust and efficient Perl solution是最佳解决方案。

这是一个纯粹的Bash实现(除了对外部实用程序mkdirmv的调用之外),它在避免错误-肯定方面也很强大:

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参数扩展将所有(//<space>-<space>个序列替换为//个字符。每个

    • 这种替换的原因是Bash的令牌分裂机制只能拆分(其中一个)单个字符。
    • 选择了辅助分隔符/,因为它保证不会包含在输入文件名中。
  • 结果通过here-string(read)传递给<<<; $IFS,内部字段分隔符,设置为辅助分隔符/,以便将文件名拆分为其成分标记。
    请注意,通过指定 3 变量名称,指定的最后一个变量将接收输入的其余部分,即使它包含分隔符的其他实例。

  • 为了安全起见,song="${song//// - }"然后将/的实例转换回<space>-<space>序列,以便最终保留未修改的歌曲部分,如果它包含此类序列。< / p>

  • mkdir -p "$artist/$album"然后为艺术家和专辑创建子文件夹;请注意,如果目标文件夹已存在,mkdir -p是一个(成功的)无操作。

  • 最后,mv命令将输入​​文件移动到其歌曲标题名称下的目标文件夹。

答案 3 :(得分:0)

bash解决方案,同时考虑到dash(-)也出现在艺术家姓名中(所有时间四分卫)。

#!/bin/bash
ls *.mp3 > /home/user/mp3songs.list
awk '{print "\""$0"\""}' /home/user/mp3songs.list

while read -r line; do
song="$line"
artist=`echo "$song"|awk -F" - " '{print$1}'`
title=`echo "$song"|awk -F" - " '{print$2}'`
name=`echo "$song"|awk -F" - " '{print$3}'`
mkdir -p "$artist"
mkdir -p "$artist"/"$title"
printf "Moving $song to $artist/$title directory"
mv "$song" "$artist"/"$title"/"$name"
done < /home/user/mp3songs.list

rm /home/user/mp3songs.list