68

As it was suggested here I am using cat command to concatenate several .mp3 files into one .mp3 file.

Imagine, I have following .mp3 files in the current folder:

001001.mp3 001002.mp3 001003.mp3 001004.mp3 001005.mp3

or, like this:

096001.mp3 096002.mp3 096003.mp3 096004.mp3

I need to concatenate these .mp3 files in there ascending sequence, i.e. 001001.mp3+001002.mp3+001003.mp3+etc.

In order to join these .mp3 files into one I am executing following command in the current folder:

cat *.mp3 > final.mp3

I tested the final .mp3 file and it is what I am expected, but I need to be sure that above command picks files in there ascending sequence.

Can I be sure that above command always concatenates files in the ascending sequence?

Thank you Sir!

1

9 Answers 9

81

cat is not the right tool for this job. The MP3 format has all sorts of junk that can lurk at the front and end of the file and this needs to be strippe out. mp3wrap is what you want. It will exclude any metadata in the files and stick the audio together.

sudo apt-get install mp3wrap
mp3wrap output.mp3 *.mp3

Before you do that, run ls *.mp3 to check that they're in the correct order. When I originally wrote this answer (over six years ago!) wildcard globs apparently didn't behave well but I think they do now.

You might need to rename the files if for example, they are numbered but aren't zero-padded, {1-11}.mp3 would be sorted by 1 10 11 2 3 4 5 6 7 8 9. This can be fixed easily.

9
  • 2
    Right - cat will mangle the mp3 file format by "creating an array" (as it were) of mp3 files within a single mp3 file. But it seems to work if the player software is smart enough.
    – user8290
    Jan 8, 2011 at 1:25
  • 1
    This worked better for me, because it handles mp3s with spaces in the filename: find . -maxdepth 1 -iname '*.mp3' -print0 | sort -z | xargs -0 mp3wrap output.mp3
    – bmaupin
    Jul 31, 2014 at 1:25
  • 1
    @bmaupin A fair point but I'm not sure why I wasn't just using Bash's wildcard expansion. *.mp3 should suffice (and works with spaces).
    – Oli
    Jul 31, 2014 at 7:49
  • Available for mac from brew package manager! $ brew install mp3wrap.
    – Rubens
    Apr 4, 2016 at 16:14
  • 1
    In bash, *.mp3 is guaranteed to preserve alphabetical order. If your files are named 09.mp3, 10.mp3, 11.mp3, that's probably what you want. If your files are named 9.mp3, 10.mp3, 11.mp3, that's probably not what you want, but you can do `ls *.mp3 | sort -n`.
    – Jo Liss
    Jul 23, 2016 at 17:48
45

mp3wrap seems to be a decent enough solution, but when I played the resulting file, the timestamp wasn't correct. It seems like mp3wrap is best used when you're joining mp3s into a file that you know you'll want to split later.

I simply wanted to permanently concatenate some mp3s together. I ended up using ffmpeg to concatenate the files:

  1. First, install ffmpeg

    • Ubuntu 15.04+

      sudo apt install ffmpeg
      
    • Ubuntu 14.10 and below
      Go to http://ffmpeg.org/download.html, download one of the static builds, untar it, and copy to /usr/local/bin

  2. ffmpeg -i "concat:file1.mp3|file2.mp3" -acodec copy output.mp3

More info: https://trac.ffmpeg.org/wiki/Concatenate#protocol
https://superuser.com/a/314245

8
  • ffmpeg is missing, but avconv replaces it: askubuntu.com/questions/432542/…
    – muru
    Jul 31, 2014 at 2:00
  • 2
    Yeah, I used avconv for a while, but then I needed some features that ffmpeg had and avconv didn't, and I haven't used it since. These days it feels like a waste of time checking to see if avconv has the features I need when I already know ffmpeg does.
    – bmaupin
    Jul 31, 2014 at 13:05
  • Please feel invited to join this bug report discussion.
    – orschiro
    Jan 25, 2016 at 8:41
  • I've tried this and it doesn't work great; try running output.mp3 thru a mp3val and you'll see all sorts of errors that will create playback issues in Chrome64+ (see bugs.chromium.org/p/chromium/issues/detail?id=794782 and bugs.chromium.org/p/chromium/issues/detail?id=806601#c10)
    – The Onin
    Feb 4, 2018 at 5:45
  • 1
    Works nicely for me. With a lot of files in the directory, to get a |-separated list of filenames that I could paste into the ffmpeg command line, I used the following: python -c 'import glob; print("|".join(sorted(glob.glob("*.mp3"))))'
    – alani
    Jun 22, 2022 at 8:06
9

Most people are suggesting mp3wrap, but it has downsides: the file generated does not report its full length in some players, and then you cannot seek past that point.

mp3cat does the job fast and well, as far as I can tell. It can be downloaded in http://mulholland.xyz/dev/mp3cat/, and used as follows:

mp3cat file1.mp3 file2.mp3 file3.mp3

another possibility would be sox

sudo apt-get install sox libsox-fmt-mp3
sox file1.mp3 file2.mp3 target.mp3

but it seems very slow (possibily it decodes and reencodes the audio?)

1
  • 1
    The quoted link no longer works; mp3cat now lives at https://www.dmulholl.com/dev/mp3cat.html Jan 10, 2022 at 9:22
8

As previously suggested, mp3wrap is a good solution. It may not work all of the time though. As far as I know, mp3wrap assumes that all the input files have the same characteristics such as VBR vs CBR, bitrate, and so on. If this assumption isn't met, it is likely to fail. In that case, the only solution would be to decode all the mp3files to a raw format like .wav, concatenate them with a program like sox and finish by re-encoding all to mp3.

2
  • Note that re-encoding mp3 files (also know as "transcoding") will result in a quality loss. I would not recommend it. May 31, 2019 at 3:51
  • @MartinTournoij Then what would you recommend as a solution where the files' encodings are too different for mp3wrap to handle?
    – Mr Lister
    Dec 9, 2021 at 13:19
5

It does an alphabetical sort based on single characters. That means that "01" comes before "1", since nought has a lower value than one.

Here's an example. I've got a directory with files named 1, 2, 3, 04, 05, and 06. They are text files that contain their own file names:

test$ cat *
04
05
06
1
2
3

So, yes it will; but you need to make sure that all your files are 'padded' properly.

This nifty line of bash script will let you visually compare the file names, making it very easy to spot any mistakes:

for f in $(ls); do printf "%05s\n" "$f"; done

It's output will look like this:

   04
   05
   06
    1
    2
    3

If they aren't, you will need to pad the file names: Bash script to pad file names on StackOverflow explains how to do it.


Edit. Vote for Oli's answer, it's much better. :P
I'll leave mine because it add something, but you should use his solution,

mp3wrap output.mp3 `ls -1 *.mp3 | sort`

Keep in mind that sort will still sort things in the way I described above, you will still need to pad file-names if they aren't equal in length.

1
  • "Lexical" or "Lexicographic" describes this sort order better than "alphabetical". "Alphabetical" is not well defined, and may be used to describe sort orders that treat spaces and other punctuation as if they did not exist.
    – mc0e
    Jul 2, 2021 at 15:54
4

I found the online service audio-joiner to work very well and preserve the correct time-stamp (contrary to mp3wrap).

1

Let me summarize the other answers:

  • mp3wrap joins mp3 files into a special "concatenated mp3 file" format, which is faster because it doesn't require re-encoding, but has the disadvantage of not being a normal mp3 file with a length and so on.

  • ffmpeg -i "concat:file1.mp3|file2.mp3" -acodec copy output.mp3 is cumbersome to type, but should work well, as it's a standard command to use for joining video files for example. However, in my testing it introduces glitches at the input file transitions.

  • sox file1.mp3 file2.mp3 target.mp3 should work great, certainly much easier to type, but it also introduces glitches in my testing.

  • Even when I use sox to first convert each .mp3 file to .wav, and then sox file1.wav file2.wav target.wav, the output contains audible glitches.

  • However, if I use mpg123 to decode the mp3 files to .wav, then I can join the .wav files with Sox and not hear glitches. This suggests that the problem with sox (and maybe ffmpeg) is in the decoding of the mp3 files.

  • mp3cat apparently works great but I was too lazy to test it, as it isn't found in my distribution's repository

It's curious that no one mentioned mpg123 yet. Although troubled by security and license issues early in its 20+ year history, it is one of the original mp3 players and should be fairly stable. Since it automatically concatenates its mp3 arguments (in a glitch-less fashion) before sending them to the sound card, we just have to use the -w option to tell it to output to a Wave file instead. Then lame encodes this back to mp3. Here's a script which accomplishes this:

#!/bin/bash
FILES=("$@")
OUTPUT=$(mktemp -t mp3-concat.XXXXXX.mp3 -u)
WAVE=$(mktemp -t mp3-concat.XXXXXX.wav -u)
mpg123 -w $WAVE ${FILES[@]}
lame $WAVE $OUTPUT
cat $OUTPUT
rm $WAVE $OUTPUT

Usage example:

$ mp3-concat file1.mp3 file2.mp3 > joined.mp3
1
perl -E'say qq(file '\''$_'\'') for <*>' *   > file.list   && ffmpeg -f concat -safe 0 -i file.list -c copy mybigfile.mp3
  1. copy this line into a terminal (where you have perl and ffmpeg available) after changing to the folder with all the files you want to concatenate
  2. it will cause an error aboute "file.list" (because "file.list" will be written into the "file.list"-file) but nevermind, it still works
  3. all in all this just writes the foldercontent into the "file.list"-file and formats it.
  4. after that it will merge the files into one mp3 file with ffmpeg
0

I love bmaupin's comment, yet it could produce natural sort of (version) numbers by using sort -V:

find . -maxdepth 1 -iname '*.mp3' -print0 | sort -Vz | xargs -0 mp3wrap ../tmp.mp3

and you don't have to deal with special characters like ' " () [] {} in the filename.

You must log in to answer this question.

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