Я постоянно вижу синтаксис
find . -name "FILENAME" -exec rm {} \;
главным образом потому, что я не понимаю, как именно эта -exec
часть работает. Что означает скобки, обратный слеш и точка с запятой? Существуют ли другие варианты использования этого синтаксиса?
man
странице POSIX читается имя утилиты или аргумент, содержащий только два символа «{}», которые должны быть заменены текущим путем , что мне кажется достаточным. Кроме того, у него есть пример-exec rm {} \;
, как в вашем вопросе. В мои дни почти не было других ресурсов, кроме «большой серой стены», книг печатныхman
страниц (бумага была дешевле, чем хранилище). Так что я знаю, что этого достаточно для кого-то нового в теме. Ваш последний вопрос, хотя справедливо задать здесь. К сожалению, ни у @Kusalananda, ни у меня нет ответа на это.xargs
иногда это удобно,find
можно передать несколько аргументов пути команде без него.-exec command... {} +
(с+
вместо\;
) пропускает столько путей после того,command...
как будет соответствовать (каждая ОС имеет свой собственный предел длины командной строки). И какxargs
, то+
-завершённый формаfind
«S-exec
действий также будет работатьcommand...
несколько раз в редких случаях, когда есть слишком много путей , чтобы поместиться в пределах.Ответы:
Этот ответ приходит в следующих частях:
-exec
-exec
в сочетании сsh -c
-exec ... {} +
-execdir
Основное использование
-exec
-exec
Опция имеет внешнюю утилиту с дополнительными аргументами в качестве аргумента и выполняет его.Если строка
{}
присутствует где-либо в данной команде, каждый ее экземпляр будет заменен на путь, который обрабатывается в данный момент (например,./some/path/FILENAME
). В большинстве оболочек эти два символа{}
не нужно заключать в кавычки.Команду необходимо завершить с помощью
;
for,find
чтобы узнать, где она заканчивается (поскольку после этого могут быть дополнительные параметры). Чтобы защитить его;
от оболочки, его нужно заключить в кавычки как\;
или';'
, иначе оболочка увидит его как конецfind
команды.Пример (
\
в конце первых двух строк только для продолжения строки):Это найдет все обычные файлы (
-type f
), имена которых соответствуют шаблону*.txt
в текущем каталоге или ниже. Затем он проверит,hello
встречается ли строка в каком-либо из найденных файлов, используяgrep -q
(который не производит никакого вывода, только состояние выхода). Для тех файлов, которые содержат строку,cat
будет выполнен вывод содержимого файла на терминал.Каждый из них
-exec
также действует как «тест» на пути, найденныеfind
, как-type
и-name
делает. Если команда возвращает нулевой статус выхода (что означает «успех»), рассматривается следующая частьfind
команды, в противном случаеfind
команда продолжается со следующим путем. Это используется в приведенном выше примере, чтобы найти файлы, содержащие строкуhello
, но игнорировать все остальные файлы.Приведенный выше пример иллюстрирует два наиболее распространенных варианта использования
-exec
:find
команды).Использование
-exec
в сочетании сsh -c
Команда, которая
-exec
может выполняться, ограничена внешней утилитой с необязательными аргументами. Использовать встроенные функции оболочки, функции, условные выражения, конвейеры, перенаправления и т. Д. Напрямую с помощью-exec
невозможно, если они не заключены в нечто вродеsh -c
дочерней оболочки.Если
bash
функции требуются, то используйтеbash -c
вместоsh -c
.sh -c
выполняется/bin/sh
со сценарием, заданным в командной строке, за которым следуют необязательные аргументы командной строки для этого сценария.Простой пример использования
sh -c
сам по себе, безfind
:Это передает два аргумента дочернему сценарию оболочки:
Строка
sh
. Это будет доступно как$0
внутри скрипта, и если внутренняя оболочка выводит сообщение об ошибке, она будет префиксом этой строки.Аргумент
apples
доступен как$1
в скрипте, и если бы было больше аргументов, тогда они были бы доступны как$2
и$3
т. Д. Они также были бы доступны в списке"$@"
(за исключением того,$0
что не было бы частью"$@"
).Это полезно в сочетании с тем,
-exec
что позволяет нам создавать произвольно сложные сценарии, которые воздействуют на найденные путиfind
.Пример: Найти все обычные файлы, которые имеют определенный суффикс имени файла, и изменить этот суффикс имени файла на другой суффикс, где суффиксы хранятся в переменных:
Внутри внутреннего скрипта,
$1
будет строкаtext
,$2
будет строкаtxt
и$3
будет любым путемfind
, найденным для нас. Расширение параметра${3%.$1}
будет принимать путь и удалять.text
из него суффикс .Или, используя
dirname
/basename
:или с добавленными переменными во внутреннем скрипте:
Обратите внимание, что в этом последнем варианте переменные
from
иto
в дочерней оболочке отличаются от переменных с одинаковыми именами во внешнем скрипте.Выше приведен правильный способ вызова произвольного сложного сценария с
-exec
помощьюfind
. Использованиеfind
в цикле, каксклонен к ошибкам и не элегантен (личное мнение). Он разбивает имена файлов на пробелы, вызывает глобализацию имени файла, а также заставляет оболочку развернуть полный результат
find
перед тем, как даже выполнить первую итерацию цикла.Смотрите также:
С помощью
-exec ... {} +
В
;
конце может быть заменен на+
. Это заставляетfind
выполнять данную команду с максимально возможным количеством аргументов (найденных путей), а не один раз для каждого найденного пути. Строка{}
должна появиться перед тем,+
как это сработает .Здесь
find
мы соберем полученные имена путей и выполнимcat
их на как можно большем количестве одновременно.Так же и здесь,
mv
будет выполнено как можно меньше раз. Этот последний пример требует GNUmv
от coreutils (который поддерживает эту-t
опцию).Использование
-exec sh -c ... {} +
также является эффективным способом зацикливания набора путей с произвольно сложным сценарием.Основы те же, что и при использовании
-exec sh -c ... {} ';'
, но теперь сценарий принимает гораздо более длинный список аргументов. Они могут быть зациклены, зацикливаясь"$@"
внутри скрипта.Наш пример из последнего раздела, который изменяет суффиксы имени файла:
С помощью
-execdir
Также есть
-execdir
(реализовано большинствомfind
вариантов, но не стандартным вариантом).Это работает как
-exec
с той разницей, что данная команда оболочки выполняется с каталогом найденного пути в качестве текущего рабочего каталога и{}
будет содержать базовое имя найденного пути без его пути (но GNUfind
все равно будет префиксом базового имени с./
, в то время как BSDfind
не буду этого делать).Пример:
Это переместит каждый найденный
*.txt
-файл в ранее существовавшийdone-texts
подкаталог в том же каталоге, где был найден файл . Файл также будет переименован, добавив.done
к нему суффикс .Это было бы немного сложнее,
-exec
поскольку нам нужно было бы получить базовое имя найденного файла,{}
чтобы сформировать новое имя файла. Нам также нужно имя каталога,{}
чтобыdone-texts
правильно найти каталог.С
-execdir
некоторыми вещами, подобными этим, становится легче.Соответствующая операция с использованием
-exec
вместо-execdir
должна будет использовать дочернюю оболочку:или же,
источник
-exec
берет программу и аргументы и запускает ее; некоторые команды оболочки состоят только из программы и аргументов, но многие этого не делают. Команда оболочки может включать перенаправление и конвейерную передачу;-exec
не может (хотя всеfind
может быть перенаправлено). Команда оболочки может использовать и; && if
т.д .;-exec
не могу, хотя-a -o
могу сделать некоторые. Команда оболочки может быть псевдонимом или функцией оболочки, или встроенной;-exec
не можешь. Команда оболочки может раскрыть переменные;-exec
не может (хотя внешняя оболочка, которая запускаетfind
банку). Команда оболочки может заменять$(command)
каждый раз по-разному;-exec
не можешь. ...-exec
не может - хотяfind
может перебирать файлы так же, как это делает большинство глобусов, так что это редко требуется.sh
самой собой, которая вполне способна на все эти вещиfind -exec cmd arg \;
не вызывать оболочку для интерпретации командной строки оболочки, она запускаетсяexeclp("cmd", "arg")
напрямую, а неexeclp("sh", "-c", "cmd arg")
(для которой оболочка в конечном итоге сделает эквивалент,execlp("cmd", "arg")
еслиcmd
не была встроена).find
аргументы после-exec
и до;
или+
составляют команду для выполнения вместе с ее аргументами, причем каждый экземпляр{}
аргумента заменяется текущим файлом (с;
),{}
а последний аргумент перед+
заменой - списком файлов. в качестве отдельных аргументов (по{} +
делу). IOW-exec
принимает несколько аргументов, оканчивающихся на;
или{}
+
.