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]