Вместо:
cmd="cat ${file}"
printf '%s\n' "Running command: '${cmd}'"
${cmd}
Либо передайте фиксированную команду в eval
, чтобы она интерпретировалась как код оболочки.
cmd='cat -- "$file"'
printf '%s\n' "Running command: '${cmd}'"
eval "$cmd"
Будет выведена Выполняемая команда: cat - "$ file"
, что, вероятно, не то, что вам нужно.
Или ( bash
) используйте printf% q
, чтобы правильно процитировать $ file
, чтобы его расширение можно было передать в eval
:
printf -v cmd 'cat -- %q' "$file"
printf '%s\n' "Running command: $cmd"
eval "$cmd"
Или, поскольку здесь это простая команда, вы можете сохранить аргументы этой простой команды в массиве:
cmd=(cat -- "$file")
printf 'Running command: '
printf ' %q' "${cmd[@]}"
printf '\n'
"${cmd[@]}"
Если вам известен один конкретный символ, который $ file
гарантированно не содержит подобных :
(обратите внимание, что :
- вполне допустимый символ в имени файла в Unix), вы можете сделать:
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
Теперь, в этом конкретном случае, вы также можете:
(PS4='Running command: '
set -x; cat -- "$file")
(будьте осторожны, сообщение отправляется на stderr).
Или даже:
PS4='Running command: ' find "$TARGET_DIR" -type f -exec sh -xc '
cat "$1"' sh {} \;
Или, чтобы не запускать так много команд sh
и cat
, используйте ksh93
, где cat
- это встроенная функция сопоставлена с / opt / ast / bin / cat и использует синтаксис {} +
для запуска как можно меньшего количества оболочек:
PS4='Running command: ' find "$TARGET_DIR" -type f -exec ksh93 -c '
PATH=/opt/ast/bin; set -x; for file do cat "$file"; done' ksh93 {} +
Для отображения содержимого файлов с заголовками и выполнения как можно меньшего количества команд в системах GNU вы также можете использовать head
:
$ find "$TARGET_DIR" -type f -exec head -vc-0 {} +
==> ./file 1 <==
1
2
==> ./file 2 <==
test
С zsh
:
zmodload zsh/mapfile
for file (**/*(D.)) printf '==> %q <==\n%s\n' $file $mapfile[$file]