在 bash 中拆分一个变量

Splitting up a variable in bash

我下载了一堆歌曲,正在尝试将其转换为 .mp3 并重命名。将.m4a文件转换成mp3ffmpeg,格式都是Artist Name - Song Name.mp3。我希望能够将歌曲名称和艺术家名称分离到它们自己的变量中,这样我就可以重命名文件并用歌曲名称和艺术家名称标记歌曲。

那么,如何将一个变量分成两个变量,每个变量分别包含艺术家姓名和歌曲名称,这两个信息在bash中用'-'分隔?

使用shell

v='Artist Name - Song Name.mp3'
v=${v%.mp3}
song=${v#* - }
artist=${v% - $song}
echo a=$artist, s=$song

这会产生输出:

a=Artist Name, s=Song Name

请注意,这种方法,就像下面的 sed 解决方案一样,在 - 第一次 出现时始终将艺术家和歌曲分开。因此,如果名称是:

v='Artist Name - Song Name - 2nd Take.mp3'

那么,输出是:

a=Artist Name, s=Song Name - 2nd Take

此方法是 POSIX,适用于 dashbusybox 以及 bash

使用 sed

$ v='Artist Name - Song Name.mp3'
$ { read -r artist; read -r song; } < <(sed 's/.mp3$//; s/ - /\n/' <<<"$v")
$ echo a=$artist s=$song
a=Artist Name s=Song Name

这假设 (1) - 的第一次出现将艺术家姓名与歌曲名称分开,并且 (2) 文件名 $v 只有一行(没有换行符) .

如果您的工具支持,我们可以通过使用 NUL 作为分隔符而不是换行符来克服第二个限制:

$ { read -r -d $'[=15=]' artist; read -r -d $'[=15=]' song; } < <(sed 's/.mp3$//; s/ - /\x00/' <<<"$v"); echo a=$artist s=$song
a=Artist Name s=Song Name

这是一个在艺术家和歌曲名称中都包含换行符的示例:

$ v=$'Artist\nName - Song\nName.mp3'
$ { read -r -d $'[=16=]' artist; read -r -d $'[=16=]' song; } < <(sed 's/.mp3$//; s/ - /\x00/' <<<"$v"); echo "a=$artist"; echo "s=$song"
a=Artist
Name
s=Song
Name

工作原理

sed命令去掉.mp3后缀,然后用换行符替换-

sed 's/.mp3$//; s/ - /\n/' <<<"$v"

sed 命令的输出由两行组成。第一行是艺术家姓名,第二行是歌曲名称。然后由两个 read 命令读取。

可以用纯的bash:

#!/bin/bash
name="Artist Name - Song Name.mp3"
songname="${name#*- }"
songnamewithoutextentions="${songname%.*}"
artistname="${name% -*}"
printf "%s\n%s\n%s\n" "$artistname" "$songname" "$songnamewithoutextentions"

输出:

Artist: Artist Name
Song: Song Name.mp3
Song name without extention: Song Name

解释:

"${name#*- }"$name

中第一个匹配-之后的字符串

"${name% -*}"$name

- 的最后一个匹配(右起第一个匹配)之前的字符串

您可以从 manual.

了解更多关于 Bash 参数扩展的信息

使用 bash 中内置的正则表达式匹配:

regex='(.*) - (.*).mp3'
[[ $v =~ $regex ]]
artist=${BASH_REMATCH[1]}
song=${BASH_REMATCH[2]}