linux - Calling commands in bash script with parameters which have embedded spaces (eg filenames) -


i trying write bash script processing on music files. here script far:

#!/bin/bash  saveifs=$ifs ifs=printf"\n\0"  find `pwd` -iname "*.mp3" -o -iname "*.flac" | while read f     echo "$f"     $arr=($(f))     exiftool "${arr[@]}" done  ifs=$saveifs 

this fails with:

[johnd:/tmp/tunes] 2 $ ./test.sh  ./test.sh: line 9: syntax error near unexpected token `$(f)' ./test.sh: line 9: `    $arr=($(f))' [johnd:/tmp/tunes] 2 $  

i have tried many different incantations, none of have worked. bottom line i'm trying call command exiftool, , 1 of parameters of command filename may contain spaces. above i'm trying assign filename $f array , pass array exiftool, i'm having trouble construction of array.

immediate question is, how construct array? deeper question how, within bash script, call external command parameters may contain spaces?

you did have call-with-possibly-space-containing-arguments syntax right (program "${args[@]}"). there several problems, though.

firstly, $(foo) executes command. if want variable's value, use $foo or ${foo}.

secondly, if want append onto array, syntax array+=(value) (or, if doesn't work, array=("${array[@]}" value)).

thirdly, please separate filenames \0 whenever possible. newlines , good, filenames can contain newlines.

fourthly, read takes switch -d, can used empty string '' specify \0 delimiter. eliminates need mess around ifs.

fifthly, careful when piping while loops - causes loop executed in subshell, preventing variable assignments inside taking effect outside. there way around this, - instead of piping (command | while ... done), use process substitution (while ... done < <(command)).

sixthly, watch process substitutions - there's no need use $(pwd) argument command when . do. (or if must have full paths, try quoting pwd call.)

tl;dr

the script, revised:

while read -r -d '' f;     echo "$f" # 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 {} + # shorter! 

edit 1

so need save output of exiftool, manipulate it, copy stuff? try this:

while read -r -d '' f;     echo "$f" # debugging?     arr+=("$f") done < <(find . -iname "*.mp3" -o -iname "*.flac" -print0) # warning: misleading syntax highlighting ahead newfilename="$(exiftool "${arr[@]}")" newfilename="$(manipulate "$newfilename")" cp -- "$some_old_filename" "$newfilename" 

you need change last bit - i've never used exiftool, don't know precisely you're after (or how it), should start.


Comments

Popular posts from this blog

php - Why I am getting the Error "Commands out of sync; you can't run this command now" -

linux - Does gcc have any options to add version info in ELF binary file? -

java - Are there any classes that implement javax.persistence.Parameter<T>? -