39

I want to convert all *.flac to *.mp3 in the specific folder.

This is what I've tried, but not works:

# change to the home directory
cd ~/music
# convert all *.flac files
ffmpeg -i *.flac -acodec libmp3lame *.mp3
# (optional: check whether there are any errors printed on the terminal)
sleep 60

How to get my goal?

6
  • 3
    did you try "FOR LOOP"? Feb 12, 2014 at 15:57
  • @DanilaLadner Not yet. Thanks for the clue.
    – Kevin Dong
    Feb 12, 2014 at 15:58
  • I wrote a script that does this, in parallel, and copies the tags over: http://tuxhelp.org/#flac-distiller
    – user136310
    Sep 29, 2015 at 19:38
  • Sorry I forget it. After convert file name become file.avi.mp3 you can use : rename "s/.avi//g" *.avi.mp3 for remove .avi.
    – user149335
    Dec 29, 2015 at 19:47
  • 1
    Give computer break after hard work.
    – MeowMeow
    Jul 13, 2018 at 14:21

16 Answers 16

68

A simple 1 liner solution: find -name "*.flac" -exec ffmpeg -i {} -acodec libmp3lame -ab 128k {}.mp3 \;

http://lewisdiamond.blogspot.ca/2012/01/converting-flac-to-mp3.html

Note that this will be applied recursively in the given directory. I.e. if you run this from your Music folder, it will convert all flacs from subfolders and produce a .mp3 next to it. You may also do it without ffmpeg by directly using flac and lame (i.e. read w/ flac, pipe to lame, output to a file .mp3), as shown in the link.

8
  • You can use -maxdepth 1 I think like in X Tian's answer to limit the recursiveness.
    – user44370
    Oct 24, 2014 at 20:00
  • 2
    Yes you can. You could also use ls piped to xargs or a for loop. I'm just making the (possibly wrong) assumption that a recursive search is more along what the OP needed (i.e. change all the .flac from my music library). Oct 24, 2014 at 20:48
  • 25
    This command is great - however; You end up with files named *.flac.mp3. Using your command, I came up with this... find -name "*.flac" -exec bash -c 'ffmpeg -i "{}" -y -acodec libmp3lame -ab 128k "${0/.flac}.mp3"' {} \;
    – Shane
    Oct 27, 2015 at 2:54
  • 3
    Yes, as I explained in the blog, I like this aspect of adding the .mp3 because it tells me this files comes from a lossless source, which should be found somewhere on my hard drive. Oct 28, 2015 at 16:23
  • 1
    @jottr See this comment here: unix.stackexchange.com/a/202978/108768 both {} and $0 are functionally equivalent parameters and both perfectly safe/standard ways to reference the filename in string execution.
    – Shane
    Jan 16, 2020 at 11:52
44

Try this:

for i in *.flac ; do 
    ffmpeg -i "$i" -acodec libmp3lame "$(basename "${i/.flac}")".mp3
    sleep 60
done
3
  • 1
    It isn't working with files containing space. How can I modify $(basename "${i/.flac}") to handle spaces?
    – ppr
    Jan 3, 2016 at 15:39
  • 1
    @ppr Try putting this line just before the for loop: IFS=$'\n' Jan 3, 2016 at 19:14
  • 6
    I solved the space issue by changing $(basename "${i/.flac}").mp3 to "$(basename "${i/.flac}").mp3" (putting quotes around it) Sep 17, 2016 at 20:02
8

If you have some white spaces in the file names:

for a in *.flac; do
  f="${a[@]/%flac/mp3}"
  ffmpeg -i "$a" -qscale:a 0 "$f"
done
0
2

GNU Parallel is made for these kind of tasks:

# change to the home directory
cd ~/music
# convert all *.flac files
parallel ffmpeg -i {} -acodec libmp3lame {.}.mp3 ::: *.flac
# (optional: check whether there are any errors printed on the terminal)
sleep 60

It will run the jobs in parallel (one job per CPU core) and make sure the output on the terminal is not mixed together.

To learn more spend 15 minutes reading chapter 1+2: https://zenodo.org/record/1146014

2
  • This looks interesting. Could you explain the what the {.}.mp3 ::: construct does? Or reference the manual section that explains it?
    – jottr
    Nov 29, 2019 at 18:32
  • There are two tools besides GNU parallel to consider: parallel from moreutils (was already installed in my Ubuntu 20.04) and xargs (I chose xargs for a script like this). More on the difference here: stackoverflow.com/a/42652097 Aug 19, 2021 at 12:07
2

I took everything I found here (and maybe on some other sites) and created a small tool to not only create mp3s of flacs recursively, but also preserve relative paths to create them elsewhere with multithread support.

oh, and yes, I see, I didn't use ffmpeg in that case, because my OSMC didn't provide packages for ffmpeg, only avconv, but since you're already here, I guess you know, it's "basically" the same - at least for the most important part. Just replace the command avconv with ffmpeg. My first runs were with the ffmpeg bin and the exact same options.

I am by no means a bash hacker, but I managed it, as my first bash script with the given demands, and maybe someone will benefit. I am open for any suggestions from your side, but so far it works for me.

my script to spin up the 4 instances, one for each core, is like this:

#!/bin/bash
# this should be quite self-explanatory 
for i in {1..4}
do
echo "started instance no: $i"
/home/osmc/transform.sh . &
# sleeping time can be shorter, this is just so, that 
# not all 4 processes will want to start with the same 
# file, during runtime collisions should not become an issue
sleep 5
done
echo "all instances started"

And the worker script like this:

#!/bin/bash
# take care of spaces
IFS=$'\n'
# my music folders, remote is the source, local the target dir
remote=/mnt/music/FLAC
local=/mnt/1tb/mp3
# for all flac files start loop
for i in $(find $remote -type f -iname '*.flac' );
do
## SET VARIABLES for PATHS and FILENAMES
## this might be able to be super short with sed and complex one-liner,
## but I s*ck at regex
fullfile=$i
# strip extension
filename="${i##*/}"
# add new extension
filename="${filename%.*}.mp3"
# get full dirname from inputfile
fulldir=$(dirname "${i}")
# strip leading dirs from full input dir
# count the dirs, add two, then you're good.
reldir="$(echo $fulldir | cut -d'/' -f5-)"
# some subdirs in my collection even have a flac subdir, you might
# ignore this, it strips only if it exists
reldir=${reldir//flac}
# combine target dir and relative dir
outdir="$local/$reldir"
# generate the full output filename for conversion
outfile="$outdir/$filename"
# create whole target directory - yes, I need it only once, but hey,
# it works, didn't want to start a if not exist statement... should I? 
mkdir -p "$outdir"
# run conversion - finally... you may want or need to replace 
# "avconv" with "ffmpeg"
avconv -n -nostats -loglevel info -i "$fullfile" -codec:a libmp3lame -qscale:a 0 "$outfile"
done

which can be found at https://github.com/erdnuesse/flac-to-mp3

1
  • welcome aboard, good effort. +1 Jan 12, 2018 at 18:00
1

I worked on @Ketan's answer using avconv, since ffmpeg doesn't work well over here.

for i in *.flac ; do 
    avconv -i "$i" "./mp3/$i".mp3
done

This converts flac files in a folder into mp3 files and moves then to an existing "mp3" folder. Files will be named in the model "original_name.flac.mp3"

1
find . -maxdepth 1 -type f -name '*.flac' | while IFS= read -r f; do
  ffmpeg -i  "$f" -acodec libmp3lame "$( sed -e's/\.flac/.mp3/g' <<< $f )"
done
1
  • 1
    sed expression needs an ending '
    – Jaime M.
    Aug 14, 2015 at 16:15
0

Parallel FTW (no doubt you have more than one core - why not use them?):

ls *flac | while read f; do ffmpeg -i "$f" -acodec libmp3lame $f.mp3 & done
1
0

For example, if you have multiple avi files:

ls *.avi | xargs -I {} ffmpeg -i {} {}.mp3
0

To recursively convert in mp3 all the flac or wav files in nested folders, I used this command:

find '~/Music/' -iname '*.flac' , -iname '*.wav' -exec bash -c 'D=$(dirname "{}"); B=$(basename "{}"); mkdir "$D/mp3/"; ffmpeg -i "{}" -ab 320k -map_metadata 0 -id3v2_version 3 -acodec libmp3lame "$D/mp3/${B%.*}.mp3"' \;

It will create a folder named "mp3" inside the one with flac or wav files and, inside the mp3 folder, it will save relative mp3 files with a bitrate of 320kbps, without keeping the old file extension in the name.

0

The file name is "wav2mp3"

#!/bin/sh
# put the script to /usr/local/sbin
EXT_IN=$1
QUALITY=$2

if [ "${EXT_IN}" = "" -o "${QUALITY}" = "" ]; then
    printf "Usage: wav2mp3 \<in_file_ext\> \<quality\> \ne.g. wav2mp3 wav 2\n"
    exit 1
fi

#String delimeter
SAVEIFS=${IFS}
IFS='
'
# List of the files in directory lower than current to array
FILES_LIST=`find . -type f  -name "*.${EXT_IN}"`
for FILE in ${FILES_LIST}; do
    echo $FILE
    PREFIX=`echo $FILE | awk -F \. 'OFS="."{ $NF="" }1' | sed 's/.$//'`
    echo $PREFIX
    ffmpeg -i $FILE -codec:a libmp3lame -qscale:a $QUALITY $PREFIX.mp3
done
1
  • Consider using shellcheck.net. It has quite a few suggestions regarding your script.
    – llogan
    Mar 29, 2019 at 17:47
0

If it can help .... I've written a small bash script to do this .... You need to have ffmpeg/flac installed.

How it works:

It takes 2 arguments :

  1. The folder of your music library (flac/ogg/mp3 ...)
  2. The destination folder (you need to create it before).

It produce :

  • An exact copy from the source folder into the destination folder, with:
    • the non flac files copied into.
    • the flac files transformed to mp3 ( VBR high quality)
  • A run.sh file with the commands to convert the flac files (this script is executed automatically).

#!/bin/bash

FLAC_PATH=$1
CONV_PATH=$2

DEBUG=0;

function usage {
  echo "";
  echo "    This script convert all flac files from a folder to mp3 files to a second folder";
  echo "";
  echo "    Usage :";
  echo "        ./conv.sh {Source Folder} {Destination Folder}";
  echo "        note : booth folder must exist before starting this script";
  echo "               files other than flac are copied to the destination folder";
  echo "";
}

if [ ! -d "$2" ]; then
  echo "";
  echo " ERROR : [$2] is not a directory.";
  usage
  exit 1
fi;

if [ ! -d "$2" ]; then
  echo "";
  echo " ERROR : [$2] is not a directory.";
  usage
  exit 1
fi;

COMMANDS="run.sh"
echo "" > run.sh
echo " convert from $FLAC_PATH to $CONV_PATH ";

find "${FLAC_PATH}" -type f |while read myFile; do
  SRC_DIR=${myFile%/*}
  SRC_FILE=${myFile##*/}
  DST_DIR=$CONV_PATH/$SRC_DIR
  mkdir -p "${DST_DIR}"
  # TEST if the file is a flac ....
  metaflac --show-md5sum "${myFile}" 2>/dev/null 1>/dev/null
  if [ $? -eq 0 ]; then
    echo -n "  *** $myFile [FLAC !] : "
    DST_FILE=${myFile%.*}
    OUT_PATH="${DST_DIR}/$( echo $SRC_FILE | sed -e 's/.flac$/.mp3/')"

    if [ $DEBUG == 1 ]; then
      echo "  SRC = $myFile";
      echo "  OUT = $OUT_PATH"
    fi;

    if [ -f "$OUT_PATH" ]; then
      echo "  exist, do nothing !";
    else
      echo "  add to compress list !";
      echo "ffmpeg -y -i \"${myFile}\" -codec:a libmp3lame -q:a 0 -map_metadata 0 -id3v2_version 3 \"${OUT_PATH}\" " >> $COMMANDS
    fi;

  else
     echo -n "  *** $SRC_FILE  [NOT FLAC] : "
     if [ -f "${CONV_PATH}/${myFile}" ]; then
       echo " exist, do nothing !"
     else
       echo "  copy."
       cp "${myFile}" "${CONV_PATH}/${myFile}"
     fi
  fi

done;

echo " And now, CONVERT THE FLAC's!!! "
sh run.sh

0

The following shell command will recursively look through all subfolders starting at the current folder, and convert all .flac files to .mp3 format, preserving file names and original directory structure.

If you want to convert all of your .flac files to .mp3, but preserve the original .flac source files, use:

find . -type f -name "*.flac" -exec bash -c 'FILE="$1"; ffmpeg -i "${FILE}" -vn -c:a libmp3lame -ab 320k -y "${FILE%.flac}.mp3";' _ '{}' \;

-ab is the desired audio bit rate for your output mp3 files (usually in the range 128k to 320k, where higher is better quality but larger file size).

If there is a problem, or you want to redo conversion of your .flac files at a higher bit rate, the original source .flac files will be preserved, and repeating the above command will overwrite your previously generated .mp3 files with new ones (the -y flag tells ffmpeg to overwrite previous output files with the same name without asking for confirmation).

Once you're happy that all the files have been converted successfully, you can then remove the original .flac files with this script:

find . -type f -name "*.flac" -exec bash -c 'FILE="$1"; rm "${FILE}";' _ '{}' \;

Alternatively, you can recursively convert all the .flac files to .mp3 and remove the original .flac files in one go with a single line of script, but use with caution, as it will delete your source files:

find . -type f -name "*.flac" -exec bash -c 'FILE="$1"; ffmpeg -i "${FILE}" -vn -c:a libmp3lame -ab 320k -y "${FILE%.flac}.mp3" && rm "${FILE}";' _ '{}' \;

If you want to recursively convert audio files from formats other than .flac to .mp3, edit the above scripts so that you replace '.flac' with the appropriate input file extension (eg. '.wav', '.wma' etc.)

0

Here is a version with ffmpeg for m4a -> mp3:

for i in *.m4a ; do 
    ffmpeg -i "$i" -acodec libmp3lame "$(basename "${i/.m4a}")".mp3
    # sleep 60
done
-1
for a in *.flac

do
OUTF=`echo "$a" | sed s/\.flac$/.mp3/g`

ffmpeg -i "$a" -acodec libmp3lame "$OUTF"


done
1
  • 3
    welcome to U&L, your answer hardly add anything to @Ketan accepted answer four years ago.
    – Archemar
    Dec 29, 2017 at 8:45
-2

I realize this comes quite late, but for memory, see my script "batchaudiocvt" on sourceforge. It is a (quite large) shell script designed for efficient mass conversion of audio files, between many formats. In particular, it makes its best to convert the usual tags.

3
  • This question is about how to handle the loop in the shell. The user already knows the command they want to use to do the conversion. Oct 31, 2018 at 23:51
  • Welcome to Stack Exchange.  Are you Eric Dujardin?  If so, it would be good to use the contact form and select ‘‘I need to merge user profiles’’ to have your accounts merged. Nov 1, 2018 at 2:19
  • Sorry, I was just trying to help with the stated goal of converting the files. Anyway the provided script may be worth a read. Nov 1, 2018 at 8:18

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .