BASH script stop after executing one line but if I use echo instead of exec the output of the script completes

StackOverflow https://stackoverflow.com/questions/21285919

  •  01-10-2022
  •  | 
  •  

Question

Background I am a newbie to Bash scripting and through Googling I have got as far as I have.

I have two text files: "Filemp3.txt" that contains

songname - artist.mp3

songname2 - artist2.mp3

songname3 - artist3.mp3

and Fileogg.txt that contains

songname - artist.ogg

songname2 - artist2.ogg

songname3 - artist3.ogg

I will be using SOX to convert from MP3 to Ogg.

I have the following bash script:

#!/bin/bash

exec 3<Fileogg.txt

while read mp3; do
        read -u3 ogg
        echo sox "Musicmp3/$mp3" "Musicogg/$ogg"
done <Filemp3.txt

This outputs exactly the commands I want to run line by line.

radio@radio:~$ ./convert-mp3-ogg.sh
sox Musicmp3/songname - artist.mp3 Musicogg/songname - artist.ogg
sox Musicmp3/songname2 - artist2.mp3 Musicogg/songname2 - artist2.ogg
sox Musicmp3/songname3 - artist3.mp3 Musicogg/songname3 - artist3.ogg

But when I edit the script to exec e.g. exec sox "Musicmp3/$mp3" "Musicogg/$ogg" ... the script runs & an ogg file is created but for only the first filename.

I am assuming this is a problem with my Bash script as the ogg file plays fine and Sox does not show any error I am aware of.

Was it helpful?

Solution

The exec command replaces the command being executed in the current process with a new command. It's like a subroutine call that never returns. In this case, you simply want to call sox, and continue after it returns, so just drop the exec:

while read mp3; do
    read -u3 ogg
    sox "Musicmp3/$mp3" "Musicogg/$ogg"
done < Filemp3.txt

OTHER TIPS

There are two unrelated meanings of exec, which is probably where you are confused. The first one you use:

exec 3<Fileogg.txt

is fine, it opens file descriptor number 3 for file 'Fileogg.txt', and is read with your read -u3.

There is a second use of exec though, and that is to replace the current program with a different one, in the same process. There is no return from a successful exec. So when you:

exec sox "Musicmp3/$mp3" "Musicogg/$ogg" 

that replaces bash with sox, so you never return to the script!

Just remove the exec, you don't need it here:

sox "Musicmp3/$mp3" "Musicogg/$ogg" 
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top