Проблема с использованием команды подстановки sed внутри опции -exec в find

Вход 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 является ошибкой? Как одинарная и двойная кавычка имеет значение в этом сценарии?

-2
30.01.2017, 01:25
2 ответа

После разбора, выполненного внешней оболочкой, третья команда состоит из слов 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".

2
28.01.2020, 05:15

Я думаю, это потому, что вы закрываете одинарную кавычку, используемую для команда 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 {} \;
2
28.01.2020, 05:15

Теги

Похожие вопросы