Вход 1:
find . -maxdepth 1 -name "* *" -exec bash -c 'sed -n '1p' <(echo $1)' h {} \;
Выход 1:
./file with space
Вход 2:
find . -maxdepth 1 -name "* *" -exec bash -c 'sed "1s_ _._" <(echo $1)' h {} \;
Выход 2:
./file.with.space
Вход 3:
find . -maxdepth 1 -name "* *" -exec bash -c 'sed '1s_ _o_' <(echo $1)' h {} \;
Выход 3:
sed: -e expression #1, char 3: unterminated `s' command
Почему выход 3 является ошибкой? Как одинарная и двойная кавычка имеет значение в этом сценарии?
После разбора, выполненного внешней оболочкой, третья команда состоит из слов find
, .
, -maxdepth
, 1
, -name
, * *
, -exec
, bash
, -c
, sed 1s_
, _o_ <(echo $1)
, h
, {}
, ;
. Слово sed 1s_
является одиночным аргументом, поскольку пробел находится внутри литерала, заключенного в одинарные кавычки, и то же самое для следующего аргумента. Таким образом, когда find
достигает . /file with space
, он запускает bash
с аргументами -c
, sed 1s_
, _o_ <(echo $1)
, h
, ./file with space
. Сценарий оболочки sed 1s_
является командой sed
с аргументом 1s_
, и это не является хорошо сформированным сценарием sed.
Вы попытались поместить строку в одинарных кавычках внутрь строки в одинарных кавычках, но это невозможно: вторая одинарная кавычка завершает строку в одинарных кавычках. Вы могли бы использовать '\''
, чтобы закончить литерал с одинарной кавычкой, затем поместить литерал в одинарную кавычку и снова начать литерал с одинарной кавычкой:
find . -maxdepth 1 -name "* *" -exec bash -c 'sed '\''1s_ _o_'\'' <(echo $1)' h {} \;
Конечно, <(echo $1)
обрывается на именах файлов, содержащих символы подстановки или пробельные последовательности, отличные от одинарного пробела. Я понятия не имею, почему вы написали это вместо <<<"$1"
.
Я думаю, это потому, что вы закрываете одинарную кавычку, используемую для команда bash -c параметр.
Итак, вы выполняете: bash
с первым аргументом -c
, вторым аргументом sed 1s_
, третьим аргументом _o_ <(echo $ 1 )
и так далее. Примерно так:
$ bash -c 'sed 1s_' '_o_ <(echo $1)'
Третий аргумент ( '_ o_ <(echo $ 1)'
) передается в bash
, а не в sed
.
Чтобы исправить вашу команду, вы должны использовать двойные кавычки для аргумента sed
:
$ find . -maxdepth 1 -name "* *" -exec bash -c 'sed "1s_ _o_" <(echo $1)' h {} \;