Reputation: 1094
I have a bunch of songs that I have downloaded that I am trying to convert to .mp3 and rename. After converting the .m4a file to mp3 with ffmpeg
, they are all in the format of Artist Name - Song Name.mp3. I want to be able to separate the Song name and Artist name into their own variables, so I can rename the file and tag the songs with the song name and artist name.
So, How can I separate a variable into two variables, each respectively containing the artist name and song name, where the two pieces of information is separated by a ' - ' in bash?
Upvotes: 3
Views: 158
Reputation: 113814
v='Artist Name - Song Name.mp3'
v=${v%.mp3}
song=${v#* - }
artist=${v% - $song}
echo a=$artist, s=$song
This produces the output:
a=Artist Name, s=Song Name
Notice that this approach, like the sed solution below, consistently divides the artist and song at the first occurrence of -
. Thus, if the name is:
v='Artist Name - Song Name - 2nd Take.mp3'
Then, the output is:
a=Artist Name, s=Song Name - 2nd Take
This approach is POSIX and works under dash
and busybox
as well as under bash
.
$ 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
This assumes (1) the first occurrence of -
divides the artist name from the song name, and (2) the file name, $v
, has only line (no newline characters).
We can overcome the second limitation by using, if your tools support it, NUL as the separator instead of newline:
$ { read -r -d $'\0' artist; read -r -d $'\0' song; } < <(sed 's/.mp3$//; s/ - /\x00/' <<<"$v"); echo a=$artist s=$song
a=Artist Name s=Song Name
Here is an example with newline characters inside both the artist and song names:
$ v=$'Artist\nName - Song\nName.mp3'
$ { read -r -d $'\0' artist; read -r -d $'\0' song; } < <(sed 's/.mp3$//; s/ - /\x00/' <<<"$v"); echo "a=$artist"; echo "s=$song"
a=Artist
Name
s=Song
Name
The sed command removes the .mp3
suffix and then replaces -
with a newline character:
sed 's/.mp3$//; s/ - /\n/' <<<"$v"
The output of the sed command consists of two lines. The first line has the artist name and the second the song name. These are then read by the two read
commands.
Upvotes: 1
Reputation: 530922
Use regular expression matching built into bash
:
regex='(.*) - (.*).mp3'
[[ $v =~ $regex ]]
artist=${BASH_REMATCH[1]}
song=${BASH_REMATCH[2]}
Upvotes: 2
Reputation: 22428
It can be done with pure 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"
Output:
Artist: Artist Name
Song: Song Name.mp3
Song name without extention: Song Name
Explanation:
"${name#*- }"
is the string after the first match of -
in $name
"${name% -*}"
is the string before the last match (first match from right) of -
in $name
You can know more about Bash parameter expansion from the manual.
Upvotes: 2