Ответ Муру подходит и подходит для случаев, когда мы хотим напечатать что-нибудь, если файл найден. Для общего случая, когда мы хотим выполнить внешнюю команду, например echo
, мы могли бы использовать -exec
флаг.
$ find . -name 'xac' -exec echo "I found " {} \; -quit
I found ./xac
{}
Часть проходит имя файла в команде между -exec
и в \;
качестве аргументов. Обратите внимание на то, что \
раньше ;
- это предотвращает неверное толкование оболочкой ; при закрытии оболочки точка с запятой означает конец команды, но при экранировании с косой чертой оболочка будет воспринимать его как обычный текст, который будет передан find
команде, а для поиска команды она служит -exec
аргументом флага закрытия .
Для построения условных if found do this; else do that
выражений мы могли бы использовать команду substitution $()
и test
command (aka [
):
$ [ "x$(find . -name 'noexist' -print -quit)" != "x" ] && echo "found" || echo "not found"
not found
$ [ "x$(find . -name 'xac' -print -quit)" != "x" ] && echo "found" || echo "not found"
found
Обращаясь к комментарию Дэна
Дан в комментариях спросил:
Разве эхо "Я нашел {}" не будет лучше, чем эхо "Я нашел" {}? Может быть, для echo это нормально, но если кто-то скопирует команду и заменит echo другой командой, у него может быть проблема
Давайте сначала поймем проблему. Обычно в оболочках есть понятие разделения слов, что означает, что переменные без кавычек и позиционные параметры будут расширяться и рассматриваться как отдельные элементы. Например, если у вас есть переменная var
и содержит hello world
текст, когда вы делаете touch $var
оболочка будет разбить его на два отдельных пунктов hello
и world
и touch
будет понятно , что , как если бы вы пытались создать 2 отдельные файлы; если вы это сделаете touch "$var"
, то оболочка будет обрабатываться hello world
как одна единица и touch
будет создавать только один файл. Это важно понимать, что это происходит только из-за того, как работают оболочки.
В отличие от этого, find
не страдает от такого поведения, потому что команды обрабатываются find
сами по себе и выполняются execvp()
системным вызовом, поэтому оболочка не участвует. Хотя фигурные скобки имеют особое значение в оболочках, поскольку они появляются в середине find
команды, а не в начале, в этом случае они не несут особого значения для оболочки. Вот пример. Давайте создадим несколько сложных имен файлов и попробуем передать их в качестве аргумента stat
команде.
$ touch with$'\t'tab.txt with$' 'space.txt with$'\n'newline.txt
$ find -type f -exec stat -c "%F" {} \; -print
regular empty file
./with?newline.txt
regular empty file
./with space.txt
regular empty file
./with?tab.txt
Как вы можете видеть, stat
получает сложные имена файлов безупречно find
, что является одной из основных причин, почему это рекомендуется для использования в переносимых скриптах, и особенно полезно, когда вы просматриваете дерево каталогов и хотите что-то сделать с именами файлов, которые потенциально могут иметь специальные символы в них. Следовательно, нет необходимости заключать фигурные скобки в команды, выполняемые в find
.
Это другая история, когда включается оболочка. Иногда вам нужно использовать оболочку для обработки имени файла. В этом случае цитирование действительно имеет значение, но важно понимать, что проблема не в поиске, а в разделении слов.
$ find -type f -exec bash -c "stat {}" sh \;
stat: cannot stat './with': No such file or directory
sh: line 1: newline.txt: command not found
stat: cannot stat './with': No such file or directory
stat: cannot stat 'space.txt': No such file or directory
stat: cannot stat './with': No such file or directory
stat: cannot stat 'tab.txt': No such file or directory
Поэтому, когда мы цитируем в оболочке , это будет работать. Но опять же, это важно для оболочки, а не find
.
$ find -type f -exec bash -c "stat -c '%F' '{}'" sh \;
regular empty file
regular empty file
regular empty file
/some/path
говорит найти, где начать искать, но ничего не говорит ему, что искать. То же самое в вашем связанном ответе. Что работает для меня этоfind /some/path -name xac -print0 -quit | grep -qz . && echo found
. Я что-то пропустил?