жучара писал(а): ↑15.02.2020 17:09
Говорили вчера, что сперва всё перечислится, что должно, а потом для каждого перечисленного выполнится команда -exec
Если быть точным, то говорили, что сперва запустится команда find, а уже она выполнит команду exec. Это ничуть не противоречит тому, что я написал. Просто в вашей команде текст
> dst не является частью команды exec.
жучара писал(а): ↑15.02.2020 17:09
А то, что вы написали про то, что > dst можно в конец переносить, так это для меня всё равно, что у меня было выражение:
2+2-2*2
А дай-ка, думаю, -2 в конец перенесу:
2+2*2-2
слов просто нет.
Вы, похоже, воспринимаете эту команду как одно большое выражение, которое компьютер должен обработать целиком, учитывая сразу все аспекты. Это не так.
Рассмотрим 2 команды:
find -exec echo $1 > dst {} \;
и
find -exec bash 'echo $1 >> dst' sh {} \;
Сначала их обработает текущий шелл. В то, в каком порядке он производит подстановки, я вдаваться не буду. В данном случае это не имеет значения, а для более сложных случаев сами прочитаете.
Первая команда: добавть
find к аргументам; добавить
-exec к аргументам; добавить
echo к аргументам; заглянуть в переменную $1 - там пусто, пропускаем; установить переадресацию
> dst (открыть файл на перезапись с нуля); добавить
{} к аргументам; добавить
; к аргументам (если бы не было экранировано, это был бы разделитель, а не аргумент).
Вторая: добавть
find к аргументам; добавить
-exec к аргументам; добавить
bash к аргументам; добавить
-c к аргументам; добавить
echo $1 >> dst к аргументам (как один большой аргумент, дословно); добавить
sh к аргументам; добавить
{} к аргументам; добавить
; к аргументам.
В первом случае получился список аргументов:
find -exec echo {} ; и установлена переадресация дескриптора 1 в уже открытый файл
dst.
Во втором:
find -exec bash -c echo $1 >> dst sh {} ; и нет переадресаций.
Теперь bash смотрит в первый аргумент (
find в обоих случаях), находит соответствующую команду (/usr/bin/find) и запускает с этим списком аргументов.
find становится для неё $0,
-exec становится $1 и т.д.
Так как bash запустил команду find, теперь работает она. Она начинает искать файлы (в первом случае они будут включать только что созданный шеллом dst), и для каждого выполняет команду exec следующим образом. Она берёт все аргументы между
-exec и
;, заменяет аргумент
{} на имя файла, находит команду, соответствующую первому аргументу, и запускает с этими аргументами.
В первом случае это команда /bin/echo, аргументы
echo имяфайла.
Во втором - команда /bin/bash, аргументы
bash -c echo $1 >> dst sh имяфайла.
В первом случае всё очевидно: команда /bin/echo выводит аргумент
имяфайла в дескриптор 1, который шелл недавно переадресовал в файл dst.
Во втором только что запущенный /bin/bash рассмотрит свои аргументы, начиная с $1, увидит
-c в $1 и выполнит следующий за ним аргумент (
echo $1 >> dst) как полноценную шелл-команду (а не просто исполняемый файл), передав ей всё, что справа он неё, в качестве аргументов, начиная с $0. Он начнёт парсить эту команду так же, как предыдущий шелл парсил ту, большую:
Добавить
echo к аргументам; прочитать $1 (в ней
имяфайла), разделить на аргументы по пробелам, добавить их все в список, тж. обработав в них шаблоны; установить переадресацию
>> dst (открыть файл на дозапись в конец).
Получились аргументы:
echo имяфайла и переадресация для этой команды дескриптора 1 в конец файла dst.
bash запустит эту команду, и она произведёт вывод. bash завершит работу, и продолжит работать find.
В первом случае find тоже продолжит работать после завершения /bin/echo.
find продолжит искать файлы и выполнять для них exec как было указано выше. Учтите, что файлы, появившиеся во время поиска, он может найти, а может и не найти. Как повезёт. В небольших каталогах обычно не находит. Во втором случае это dst, только что созданный запущенным через -exec башем; в первом таких нет - dst создан ранее, и будет гарантированно найден.
К слову, при беглом взгляде на эти команды всё это должно прокручиваться у вас в голове за долю секунды.