4

for a single .mp3, I can convert it to wav using

sox ./input/filename.mp3 ./output/filename.wav

I tried:

#!/bin/bash
for i in  $(ls *mp3)
do
    sox -t wav $i waves/$(basename $i)
done

But it throws the following error:

sox FAIL formats: can't open input file `filename.mp3': WAVE: RIFF header not found

How would I run this sox conversion over all mp3 files in the input folder and save the generated wav's to the output folder?

PS : I don't know why it shows the file enclosed between a back quote ( ` ) and an apostrophe '

`filename.mp3'

I played all the mp3's and they work perfectly file.

  • 1
    Regarding the back quote (`) and apostrophe ('), see this, this, this, this,  … (Cont’d) – G-Man Feb 21 '18 at 3:23
  • 1
    (Cont’d) … this, and this. What none of those threads mentions is that some error messages also use that convention. – G-Man Feb 21 '18 at 3:23
4

It sounds like you're running into a problem with spaces in the filename. If you have a file named "My Greatest Hits.mp3", your command will try to convert the three different files named "My", "Greatest", and "Hits.mp3". Instead of using the "$()" syntax, just use "*.mp3" in the for line, and make sure to quote the file names in the sox command.

In addition, the basename command doesn't remove the file extension, just any folder names. So this command will create a bunch of WAV files with a ".mp3" extension. Adding "-s .mp3" to the command tells basename to strip the extension, and then put ".wav" on the end adds the correct extension.

Put it all together, and you have this:

for i in *.mp3
do
    sox "$i" "waves/$(basename -s .mp3 "$i").wav"
done
  • 1
    You should quote the $i inside the `…`, too.  And, just for clarity, you might want to change `…` to $(…) — see this, this, and this. – G-Man Feb 20 '18 at 23:33
  • 1
    If you'll notice, I did put $i inside the backticks. But I get what you mean by using $() instead. I'll edit my answer. – HiddenWindshield Feb 21 '18 at 0:51
  • 1
    Yes, I know that you put the $i inside the `…` (and thanks for changing that to $(…), by the way).  What I said was that you should quote the $i inside the command substitution, like this: "waves/$(basename -s .mp3 "$i").wav".  Try your version with i="foo bar.mp3". – G-Man Feb 21 '18 at 2:30
  • 1
    Ok, I understand what you're saying now. And you're right. I'll edit again. – HiddenWindshield Feb 21 '18 at 2:55
  • 1
    I would up vote you, except I already did.    :-)    ⁠ – G-Man Feb 21 '18 at 3:03
1

First, don't use ls like that, it doesn't actually do anything, since it's the shell that actually generates the filenames in the glob *mp3 anyway. Plus it breaks if any of your files have whitespace in their names.

As for the error, I think sox here tries to interpret the MP3 file as a wav, since you gave the -t wav flag. I think you could do without it, as you did in the single-file case. You just need to change the extension on the output file name too. basename can remove the suffix too, if you tell it what to remove.

#!/bin/bash
for i in *.mp3
do
    sox "$i" "waves/$(basename "$i" .mp3).wav"
done

(The backtick-apostrophe is an ancient custom of `quoting' the file name. I the backtick is supposed to look like the left-side quotation mark, the one that looks like a rotated comma (see examples on Wikipedia). But technically, it's wrong, and it looks awful in most current fonts.)

  • thanks for the answer. in case I want it to take an input directory from a particular folder , how would I do that ex ./input/media – kRazzy R Feb 20 '18 at 23:42
  • 1
    @kRazzyR, just put the directory in the pattern: for i in /some/path/*.mp3 ... and fix the destination directory as required. basename removes the directory from the file name anyway, so that part's not a problem. – ilkkachu Feb 21 '18 at 8:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.