Em vez de:
cmd="cat ${file}"
printf '%s\n' "Running command: '${cmd}'"
${cmd}
Transmita um comando fixo para eval para que ele seja interpretado como código de shell.
cmd='cat -- "$file"'
printf '%s\n' "Running command: '${cmd}'"
eval "$cmd"
Isso gerará Running command: cat -- "$file" , o que provavelmente não é o que você deseja.
Ou ( bash specific) use printf %q para citar $file corretamente para que sua expansão possa ser passada para eval :
printf -v cmd 'cat -- %q' "$file"
printf '%s\n' "Running command: $cmd"
eval "$cmd"
Ou, como é um comando simples aqui, você pode armazenar os argumentos desse simples comando em uma matriz:
cmd=(cat -- "$file")
printf 'Running command: '
printf ' %q' "${cmd[@]}"
printf '\n'
"${cmd[@]}"
Se você souber de um caractere em particular que $file tem a garantia de não conter : (note que : é um caractere perfeitamente válido em um nome de arquivo no Unix), você poderia fazer:
cmd="cat:--:$file"
IFS=: # split on :
set -f # disable glob
# use the split+glob operator by leaving the variable unquoted:
printf 'Running command: '
printf ' %q' $cmd
printf '\n'
$cmd
Agora, neste caso específico, você também pode fazer:
(PS4='Running command: '
set -x; cat -- "$file")
(cuidado, a mensagem vai para stderr).
Ou até mesmo:
PS4='Running command: ' find "$TARGET_DIR" -type f -exec sh -xc '
cat "$1"' sh {} \;
Ou para evitar a execução de muitos comandos sh e cat , use ksh93 onde cat é um mapeado para / opt / ast / bin / cat e use a sintaxe {} + para executar o mínimo conchas possíveis:
PS4='Running command: ' find "$TARGET_DIR" -type f -exec ksh93 -c '
PATH=/opt/ast/bin; set -x; for file do cat "$file"; done' ksh93 {} +
Para exibir o conteúdo de arquivos com cabeçalhos e executar o menor número de comandos possível, nos sistemas GNU, você também pode usar head :
$ find "$TARGET_DIR" -type f -exec head -vc-0 {} +
==> ./file 1 <==
1
2
==> ./file 2 <==
test
com zsh :
zmodload zsh/mapfile
for file (**/*(D.)) printf '==> %q <==\n%s\n' $file $mapfile[$file]