Использование подстановочного знака для создания выходного файла, а не только входного файла, с ошибкой sh - PullRequest
0 голосов
/ 09 апреля 2019

Предположим, это дерево файлов:

$PWD
____dir1
________file.one
________file.two
____dir2
________file.one
________file.two

Я хочу заменить содержимое file.one в каждом каталоге на содержимое соответствующего file.two втот же каталог.

Я использую следующий код для выполнения этой простой задачи:

cat ./*1/*.one > ./*1/*.two
cat ./*2/*.one > ./*2/*.two

Он работает как задумано, НО, когда я пытаюсь выполнить это следующим образом:

/bin/sh -c 'cat ./*1/*.one > ./*1/*.two'

/bin/sh: ./*1/*.two: No such file or directory

Произошла следующая ошибка ^^.

ПРИМЕЧАНИЕ. Когда я использую Bash вместо Shell, все работает даже с флагом -c.

1 Ответ

0 голосов
/ 09 апреля 2019

Код, о котором идет речь, чрезвычайно хрупок. Если вы сгенерируете свое выходное имя из имени входного файла и не будете предполагать, что оно уже существует (и что есть ровно одно совпадение), вы находитесь на более прочном основании:

set -- ./*1/*.one                 # replace "$@" with list of matches for ./*1/*.one
for arg do                        # this is shorthand for: for arg in "$@"; do
  [ -e "$arg" ] || continue       # ignore files that don't exist (f/e, failed matches)
  cat "$arg" >"${arg%.one}.two"   # use a PE to replace .one with .two in output name
done

... то есть, следующее работает по назначению на всех POSIX-совместимых оболочках:

sh -c 'set -- ./*1/*.one; for arg do [ -e "$arg" ] || continue; cat "$arg" >"${arg%.one}.two"; done'

См. вики-страницу bash-hackers по расширению параметров для получения подробной информации о синтаксисе ${arg%.one}.

...