从终端中的 id3v1 标签重命名文件

rename files from id3v1 tags in terminal

我有一个 mp3 文件目录,它们都命名为 1.mp3、2.mp3 等。

#dir with numbers for names

10.mp3  15.mp3  2.mp3   24.mp3  29.mp3  33.mp3  38.mp3  42.mp3  47.mp3  51.mp3  56.mp3  60.mp3  65.mp3  7.mp3   74.mp3  79.mp3  83.mp3  88.mp3  92.mp3
11.mp3  16.mp3  20.mp3  25.mp3  3.mp3   34.mp3  39.mp3  43.mp3  48.mp3  52.mp3  57.mp3  61.mp3  66.mp3  70.mp3  75.mp3  8.mp3   84.mp3  89.mp3  93.mp3
12.mp3  17.mp3  21.mp3  26.mp3  30.mp3  35.mp3  4.mp3   44.mp3  49.mp3  53.mp3  58.mp3  62.mp3  67.mp3  71.mp3  76.mp3  80.mp3  85.mp3  9.mp3   94.mp3
13.mp3  18.mp3  22.mp3  27.mp3  31.mp3  36.mp3  40.mp3  45.mp3  5.mp3   54.mp3  59.mp3  63.mp3  68.mp3  72.mp3  77.mp3  81.mp3  86.mp3  90.mp3  95.mp3
14.mp3  19.mp3  23.mp3  28.mp3  32.mp3  37.mp3  41.mp3  46.mp3  50.mp3  55.mp3  6.mp3   64.mp3  69.mp3  73.mp3  78.mp3  82.mp3  87.mp3  91.mp3  96.mp3

我写了一个 for 循环来使用 ffmpeg 从元数据中提取标题:

for x in *.mp3; do
ffmpeg -i $x ./$("ffmpeg -i $x 2>&1 |grep -E '^\s*title\s*\:\s.*$' |awk -F ' :' '{print }'".mp3
done

我没有提取标题并重命名文件,而是说文件“.mp3”已经存在,我想重写它吗?当我输入 y 重写这个新的“.mp3”时,同样的事情又发生了。 我通过将输出文件的完整路径放在双引号中而不只是标题提取命令

来解决这个问题
for x in *.mp3; do
ffmpeg -I $x "./$(ffmpeg -i $x 2>&1 |grep -E '^\s*title\s*\:\s.*$' |awk -F ' :' '{print }'
)".mp3
done

我的问题是,当我只将标题提取命令用引号括起来而不是整个路径时,为什么它会创建一个名为 .mp3 的新文件?

很抱歉,如果这有点冗长,我是堆栈溢出的新手

在命令替换$(command)中,你不应该换行命令 用双引号作为 $("command") 特别是当命令包含时 options and/or 管道序列,因为双引号字符串是 视为单个命令。
请看

的区别
echo $("ls")

echo $("ls -la")

第一个有效,但第二个无效,因为 bash 解释 ls -la 作为单个命令,而不是 ls 命令后跟 -la 选项。

顺便说一句,如果你只是想重命名文件,而不是重新编码(这可能会降低质量),你可以 说:

for f in *.mp3; do
    title=$(ffmpeg -i "$f" 2>&1 | awk '/title/ {sub(/.*title\s*:\s*/, ""); print; exit}')
    mv -i -- "$f" "$title".mp3
done

最后一个 exit 用于极端情况,mp3 文件包含多个 title 元数据。

[更新]
正如@llogan 评论的那样,ffprobe 更能提取媒体信息 的文件。请改为尝试:

for f in *.mp3; do
    title=$(ffprobe -v error -of csv=p=0 -show_entries format_tags=title "$f")
    mv -- "$f" "$title".mp3
done