在 bash 中拆分一个变量
Splitting up a variable in bash
我下载了一堆歌曲,正在尝试将其转换为 .mp3 并重命名。将.m4a文件转换成mp3后ffmpeg
,格式都是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,适用于 dash
和 busybox
以及 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]}
我下载了一堆歌曲,正在尝试将其转换为 .mp3 并重命名。将.m4a文件转换成mp3后ffmpeg
,格式都是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,适用于 dash
和 busybox
以及 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]}