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?

+3


source to share


3 answers


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

.

+1


source


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 .

+2


source


Use regex built in bash

:

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

      

+2


source







All Articles