Variable splitting in bash
I have a bunch of songs that I have uploaded which I am trying to convert to .mp3 and rename. After converting the .m4a file to mp3 using ffmpeg
, they are all in Artist Name - Song Name.mp3 format. I want to be able to split the song name and artist name into my own variables, so I can rename the file and tag the songs with the song name and artist name.
So how can I split a variable into two variables, each containing an artist name and a song name, where the two pieces of information are separated by "-" in bash?
source to share
Using the shell
v='Artist Name - Song Name.mp3'
v=${v%.mp3}
song=${v#* - }
artist=${v% - $song}
echo a=$artist, s=$song
This results in the output:
a=Artist Name, s=Song Name
Note that this approach, like sed's solution below, divides artist and song sequentially on first occurrence -
. 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
.
Using 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
This assumes: (1) the first occurrence -
divides the artist name with the song name and (2) the filename $v
has only a string (newline characters).
We can overcome the second limitation by using, if your tools support it, NUL as a separator instead of a 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's an example with newlines inside the artist name and song:
$ 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
How it works
The sed command removes the suffix .mp3
and then replaces it with -
a newline:
sed 's/.mp3$//; s/ - /\n/' <<<"$v"
The sed output is two lines. The first line has the name of the artist and the second has the title of the song. Then they are read by two commands read
.
source to share
This 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 line after the first match -
in$name
"${name% -*}"
- the line before the last match (first match from the right) -
in$name
You can read more about Bash parameter expansion from the manual .
source to share