Search code examples
bashaudioterminalconcatenationsox

Concatenate files in subfolders with sox


I have a folder with subfolders containing wav files I need to concatenate, resulting in 1 wav file per folder.

In each individual folder I can use sox to do: sox *.wav combined.wav but I have 1000 folders.

How to I:

a) write a command (using Mac terminal) to concatenate all files within the subfolders for each subfolder? b) make sure the resulting file has a suitable name e.g. the name of the subfolder?

I have tried to exemplify my file structure below:

e.g.

Audio Files

170

170_a.wav

170_b.wav

170_c.wav

170_d.wav

171

171_a.wav

171_b.wav

171_c.wav

171_d.wav

etc.

And I would like to end up with 170_combined.wav and 171_combined.wav etc.


Solution

  • You can try using find

    find . -type d -exec bash -O nullglob -c 'cd "$0" && files=(*.wav) && ((${#files[@]})) && echo sox "${files[@]}" "${0##*/}_combined.wav"' {} \;
    
    • That will not do anything but print the output to stdout.

    • Remove the echo if you think the output is ok, so it will actually convert the files.

    A brief explanation.

    • -type d means find will look for directory only.

    • -exec is use so we can call/invoke a shell to do a shell tasks.

    • bash -O nullglob Just in case there are no files the glob *.wav will not expand. ( no files will be added to the array files )

    • -c Execute a shell commands

    • cd "$0" && go inside on each directory && run the next command if the command before it succeeded.

    • files=(*.wav) && Create an array of *.wav files

    • ((${#files[@]})) If array is not empty ( there are *.wav files )

    • sox "${files[@]}" "${0##*/}_combined.wav Run sox on all the *.wav files, the "${0##*/} strips the filename from the path name.