1

On this .ogg files

$ tree
.
├── Disc 1 - 01 - Procrastination.ogg
├── Disc 1 - 02 - À carreaux !.ogg
├── Disc 1 - 03 - Météo marine.ogg
└── mp3

I try with a while loop to ffmpeg convert them to mp3 keeping spaces in filenames::

$ ls *.ogg | while read line; do ffmpeg -i "$line" mp3/"$line".mp3 ; done

But I get this error::

$ ls *.ogg | while read line; do ffmpeg -i "$line" mp3/"$line".mp3 ; done
...
Parse error, at least 3 arguments were expected, only 0 given
in string ' 1 - 02 - À carreaux !.ogg' ...
...

This report bash ffmpeg find and spaces in filenames even if it look similar is for a more complicate script and has no answer.

This ffmpeg not working with filenames that have whitespace only fix it when output is a http:// URL

user3313834
  • 7,327
  • 12
  • 56
  • 99

2 Answers2

6

Use find -print0 to get the NUL-separated list of files, instead of parsing ls output which is never a good idea:

#!/bin/bash

while read -d '' -r file; do
  ffmpeg -i "$file" mp3/"$file".mp3 </dev/null
done < <(find . -type f -name '*.ogg' -print0)

You can use a simple glob to do this as well:

shopt -s nullglob # make glob expand to nothing in case there are no matching files
for file in *.ogg; do
  ffmpeg -i "$file" mp3/"$file".mp3
done

See:

codeforester
  • 39,467
  • 16
  • 112
  • 140
  • 1
    The for loop with shopt ... works very well ; but the while did not work. ffmpeg hang at the end of the first file: """... Output #0, mp3, to 'mp3/./Disc 1 - 02 - À carreaux !.ogg.mp3':size= 378kB time=00:00:24.16 bitrate= 128.2kbits/s speed=48.3x Enter command: |all – user3313834 Apr 30 '18 at 18:53
  • 1
    @user3313834, put ` – Charles Duffy Apr 30 '18 at 19:36
2

You don't need a loop here; let find execute the command for you.

find . -type f -name '*.ogg' -exec ffmpeg -i {} mp3/{}.mp3 \;

Or, if you want to strip the .ogg extension from the result:

find . -type f -name '*.ogg' -exec sh -c 'ffmpeg -i "$1" mp3/"${1%.ogg}.mp3"' _ {} \;

Conversely, you can skip find altogether:

shopt -s extglob
for f in **/*.ogg; do
  [[ -f $f ]] || continue
  ffmpeg -i  "$f" mp3/"${f%.ogg}.mp3"
done
chepner
  • 497,756
  • 71
  • 530
  • 681
  • for your first answer, I guess that ``\;`` is missing – user3313834 Apr 30 '18 at 19:00
  • for the second it work's but I don't understand what is ``_ {}`` at the end – user3313834 Apr 30 '18 at 19:01
  • When you run `sh -c '...'`, the next argument sets the value of `$0` in the new shell. You rarely care what that value is; I use `_` as a dummy value. `{}` is the current file passed by `find`, which the shell accesses as `$1`. – chepner Apr 30 '18 at 19:03