I want to merge splited audio files in sub folder with Sox. I have this basic script


# Example: sox_merge_subfolder.sh input_dir/ output_dir/

# Soure directory with subfolder that contains splitted mp3

# Set the directory you want for the merged mp3s

# make sure the output directory exists (create it if not)
mkdir -p "$output_dir"

find "$input_dir" -type d -print0 | while read -d $'\0' file
  echo "Processing..."
  cd "$file"
  output_file="$output_dir/${PWD##*/} - Track only.mp3"
  echo "  Output: $output_file"
  sox --show-progress *.mp3 "$output_file"

It is working but I would like to switch to a command that use only folders that contains mp3. To avoid error like sox FAIL formats: can't open input file '*.mp3': No such file or directory

I have this command that work find . -maxdepth 2 -name "*.mp3" -exec dirname {} \; | uniq. But the path are relative and I fail to include it into my existing script.

2 Answers 2


We can still use find to find all directories, but the loop that takes those directories will have to test for MP3 files:



mkdir -p "$outdir" || exit 1

find "$indir" -type d -exec bash -O nullglob -c '
    outdir=$1; shift

    for dirpath do
        mp3files=( "$dirpath"/*.mp3 )
        [[ ${#mp3files[@]} -eq 0 ]] && continue

        printf -v outfile "%s - Track only.mp3" "${dirpath##*/}"

        sox --show-progress "${mp3files[@]}" "$outdir/$outfile"
    done' bash "$outdir" {} +

This /bin/sh script runs find and find runs a short in-line bash script. The bash script will be called with batches of pathnames to directories, but the first argument will be the pathname of the output directory. This is received in outdir in the bash script, and that argument is shifted off the list of positional parameters, leaving only a list of directory pathnames.

The in-line script then iterates over these directories, and expands tho glob *.mp3 in each, yielding a list of pathnames for MP3 files that we store in the mp3files array.

Since we use -O nullglob for this script, the array will be empty if there are no matching filenames, so the -eq 0 test is used to skip to the next iteration if this is the case.

We then construct the output filename from the current directory pathname, and run the sox command on the collected MP3 filenames.

See also:


This does the cd in a subshell

#!/usr/bin/env bash

shopt -s nullglob


mkdir -p "$output_dir"

while IFS= read -rd '' dir; do
  if (( ${#files[*]} )); then
     cd "$dir" || exit
     echo " Output: $output_file"
     echo sox --show-progress "${files[@]##*/} "$output_file"
done < <(find "$input_dir" -type d -print0)
  • Remove the echo before the sox If you think the output is correct.
  • I have never used sox before just so you know.

You must log in to answer this question.

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