Что означает «{} \;» в команде поиска?

38

Иногда я вижу следующую команду:

find . -name  * -exec ls -a {} \;

Меня попросили выполнить это.

Что {} \;значит здесь?

codeofnode
источник
2
-name *избыточно
Кевин
3
Также ознакомьтесь с снарядом для других типов вопросов, как этот. Вот вывод для вашей команды. ,
Glutanimate
10
-name *это хуже, чем избыточно. Поскольку *кавычка не заключена в кавычки, оболочка расширяет ее до списка имен файлов в текущей папке, с пробелами, которые обрабатываются некорректно, что приводит к непредвиденным результатам или сообщению об ошибке. В качестве дополнительного пункта, findимеет много функций, одна из которых заключается в перечислении файлов; это позволяет избежать необходимости использовать -exec. Например, вы можете использовать find . -printили find . -ls. Наконец, есть два пути , чтобы избежать запятой: либо , как вы сделали с обратным косыми чертами, \;или процитировать: ';'. Используйте то, что вам удобнее.
Пэдди Ландау

Ответы:

49

Если вы запускаете findс exec, {}расширяется до имени файла каждого файла или каталога, найденного с помощью find(так что lsв вашем примере получает каждое найденное имя файла в качестве аргумента - обратите внимание, что оно вызывает lsили любую другую команду, указанную вами один раз для каждого найденного файла).

Точка с запятой ;завершает команду, выполненную exec. Его необходимо экранировать, \чтобы оболочка, findвнутри которой вы работаете , не воспринимала его как свой собственный специальный символ, а передавала его find.

Смотрите эту статью для более подробной информации.


Кроме того, findобеспечивает некоторую оптимизацию с помощью exec cmd {} +- при таком запуске findдобавляет найденные файлы в конец команды, а не вызывает ее один раз для каждого файла (так что команда запускается только один раз, если это возможно).

Разница в поведении (если не в эффективности) легко заметна, если запустить с ls, например,

find ~ -iname '*.jpg' -exec ls {} \;
# vs
find ~ -iname '*.jpg' -exec ls {} +

Предполагая, что у вас есть несколько jpgфайлов (с достаточно короткими путями ), результатом является одна строка на файл в первом случае и стандартное lsповедение отображения файлов в столбцах для последнего.

moon.musick
источник
1
Я думаю, что было бы полезно для вас по сравнению \;с +.
Кевин
Чем он отличается от find . -name * | ls -a -?
Андраш Хаммер
@DrH Смысл не в том, чтобы shell выполнил подстановочный знак, а в том, чтобы передать выражение с подстановочным знаком find. Кроме того, вывод lsв этом случае, очевидно, не зависит от ввода - независимо от того, что я использую в качестве фильтра find, lsпросто отображает содержимое рабочего каталога и все. Проверьте, например, find ~ -iname '*.jpg' -exec ls -a {} \;против find ~ -iname '*.jpg' | ls -a.
moon.musick
@DrH или даже echo 'foo' | ls -a.
moon.musick
@ moon.musick, я полагаю, что вы пропустили главное -в своей ls -a -команде, когда проверяли, что запрашивает @ dr-h.
Даниэль Ллевеллин,
21

С man-страницы для findкомандыЗначок Manpage :

-exec command ;
              Execute  command;  true if 0 status is returned.  All following arguments to find are taken to be arguments to
              the command until an argument consisting of `;' is encountered.  The string `{}' is replaced  by  the  current
              file name being processed everywhere it occurs in the arguments to the command, not just in arguments where it
              is alone, as in some versions of find.  Both of these constructions might need to be escaped (with a  `\')  or
              quoted  to  protect them from expansion by the shell.

Итак, вот объяснение:

{}означает «вывод find». Как и в «все, что findнайдено». findвозвращает путь к файлу, который вы ищете, верно? Так что {}заменяет его; это заполнитель для каждого файла, который findнаходит команда (взято отсюда ).

\;Часть в основном говорит find«хорошо, я сделал с командой я хотел выполнить».

Пример:

Допустим, я нахожусь в каталоге, полном .txtфайлов. Затем я запускаю:

find . -name  '*.txt' -exec cat {} \;

Первая часть, find . -name *.txtвозвращает список .txtфайлов. Вторая часть -exec cat {} \;будет выполнять catкоманду для каждого файла , найденного find, так cat file1.txt, cat file2.txtи так далее.

Алаа али
источник
4
Часть *.txtдолжна быть указана как '*.txt'. Это потому, что если .txtв текущей папке есть файлы, оболочка раскроет это, и вы получите неправильные результаты или сообщение об ошибке. find -name '*.txt' -exec cat {} \;
Пэдди Ландау
@Алаа Али очень хорошо объяснил
пушя