You actually did have the call-with-possibly-space-containing-arguments syntax right (program "${args[@]}"
). There were several problems, though.
Firstly, $(foo)
executes a command. If you want a variable's value, use $foo
or ${foo}
.
Secondly, if you want to append something onto an array, the syntax is array+=(value)
(or, if that doesn't work, array=("${array[@]}" value)
).
Thirdly, please separate filenames with \0
whenever possible. Newlines are all well and good, but filenames can contain newlines.
Fourthly, read
takes the switch -d
, which can be used with an empty string ''
to specify \0
as the delimiter. This eliminates the need to mess around with IFS
.
Fifthly, be careful when piping into while
loops - this causes the loop to be executed in a subshell, preventing variable assignments inside it from taking effect outside. There is a way to get around this, however - instead of piping (command | while ... done
), use process substitution (while ... done < <(command)
).
Sixthly, watch your process substitutions - there's no need to use $(pwd)
as an argument to a command when .
will do. (Or if you really must have full paths, try quoting the pwd
call.)
tl;dr
The script, revised:
while read -r -d '' f; do
echo "$f" # For debugging?
arr+=("$f")
done < <(find . -iname "*.mp3" -o -iname "*.flac" -print0)
exiftool "${arr[@]}"
Another way
Leveraging find
's full capabilities:
find . -iname "*.mp3" -o -iname "*.flac" -exec exiftool {} +
# Much shorter!
Edit 1
So you need to save the output of exiftool
, manipulate it, then copy stuff? Try this:
while read -r -d '' f; do
echo "$f" # For debugging?
arr+=("$f")
done < <(find . -iname "*.mp3" -o -iname "*.flac" -print0)
# Warning: somewhat misleading syntax highlighting ahead
newfilename="$(exiftool "${arr[@]}")"
newfilename="$(manipulate "$newfilename")"
cp -- "$some_old_filename" "$newfilename"
You probably will need to change that last bit - I've never used exiftool
, so I don't know precisely what you're after (or how to do it), but that should be a start.