Shell – ny way to use xargs across a pipe

inotifypipeshellxargs

I'm trying to automatically convert flac files moved to a folder into mp3 in another folder.

My current line of code is this:

inotifywait -m -r -q -e moved_to --format "'%w%f'" ~/test |  xargs -I x flac -cd x - | lame -b 320 - /media/1tb/x.mp3

To explain how this works so far, inotifywait monitors ~/test recursively for files moved there, outputting the path and filename to a pipe. xargs takes that name and creates the proper flac command, replacing x with the filename and decoding the file to another pipe. In the new pipe lame processes the output of flac into mp3 under /media. I want xargs to either reach across the pipe in some way, replacing the x in the lame command or in some way send it to a variable both commands can access or something. I tried messing around with named pipes and that jazz but the fact that there is actual data being piped between the two commands has me in way over my head.

Best Answer

If I understand correctly, you want to fire up one instance flac … | lame … for each input line, and interpolate the input into the arguments to both commands.

Since you need xargs to start a pipeline, you need to make it start a program that's capable of creating pipelines, i.e. a shell.

inotifywait -m -r -q -e moved_to --format "%w%f" ~/test |
xargs -l sh -c 'flac -cd "$0" - | lame -b 320 - "/media/1tb/$0.mp3"'

Alternatively, have the calling shell read lines one by one and run the pipeline.

inotifywait -m -r -q -e moved_to --format "%w%f" ~/test |
while IFS= read -r file; do
  flac -cd "$file" - | lame -b 320 - "/media/1tb/$file.mp3"
done

Note that the format %w%f produces an absolute path, to which you're prepending /media/1tb and appending .mp3. If you want to strip off the directory part of the file in the lame command, change $file to ${file##*/}. If you want to strip off the extension, change $file to ${file%.*}. If you want to do both, you'll have to do it in two steps. If you want to reproduce the directory hierarchy under /media/1tb, you can use mkdir -p.

cd ~/test
inotifywait -m -r -q -e moved_to --format "%w%f" . |
while IFS= read -r file; do
  [ -f "$file" ] || continue; # skip directories and other special files
  dir=${file%/*}; file=${file##*/}
  mkdir -p "/media/1tb/$dir"
  flac -cd "$dir/$file" - | lame -b 320 - "/media/1tb/$dir/${file#.*}.mp3"
done
Related Question