Использование соединителей после команды поиска

10

Я хочу, чтобы мой bash печатал 'found', только если что-то найдено, используя команду find. Но использование && не помогает: даже если ничего не найдено, я печатаю «найдено». Пример:

$ pwd
/data/data/com.termux/files/home/test/test1/test4
$ ls
xaa  xab
$ find . -name xac && echo 'found'
found
$ find . -name xaa && echo 'found'
./xaa
found
Йозеф Климук
источник

Ответы:

18

Вы можете сделать findсебе печать found:

find . -name xac -printf "found\n" -quit

-quitЗаставят find бросить курить после первого матча , так что foundпечатаются только не более одного раза.

В аналогичном потоке в Unix и Linux ( make find fail, когда ничего не было найдено ), я использовал grep -qzдля возврата ненулевое состояние выхода, если findничего не найдено:

find /some/path -print0 -quit | grep -qz .

Что вы можете использовать для создания составных команд, используя &&или if:

find /some/path -print0 -quit | grep -qz . && echo found
Мур
источник
Я должен был смотреть на это некоторое время. /some/pathговорит найти, где начать искать, но ничего не говорит ему, что искать. То же самое в вашем связанном ответе. Что работает для меня это find /some/path -name xac -print0 -quit | grep -qz . && echo found. Я что-то пропустил?
Джо
@ Джо, что здесь важно, так это -print0 -quit. То, что вы положили до этого, зависит от того, что вы хотите найти. Я решил опустить это здесь.
Муру
13

Ответ Муру подходит и подходит для случаев, когда мы хотим напечатать что-нибудь, если файл найден. Для общего случая, когда мы хотим выполнить внешнюю команду, например echo, мы могли бы использовать -execфлаг.

$ find . -name 'xac' -exec echo "I found " {} \; -quit             
I found  ./xac

{}Часть проходит имя файла в команде между -execи в \;качестве аргументов. Обратите внимание на то, что \раньше ;- это предотвращает неверное толкование оболочкой ; при закрытии оболочки точка с запятой означает конец команды, но при экранировании с косой чертой оболочка будет воспринимать его как обычный текст, который будет передан findкоманде, а для поиска команды она служит -execаргументом флага закрытия .


Для построения условных if found do this; else do thatвыражений мы могли бы использовать команду substitution $()и testcommand (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
Сергей Колодяжный
источник
Не было echo "I found {}"бы лучше, чем echo "I found " {}? Может быть, для echo это нормально, но если кто-то скопирует команду и заменит echo другой командой, у него может быть проблема.
Дан
@ Дан тема была слишком длинной для обсуждения в комментариях, поэтому я внес изменения в свой ответ. Пожалуйста, смотрите
Сергей Колодяжный,
1
Спасибо за то, что наконец понял, почему эта точка с запятой должна быть там. Также отличное объяснение цитирования.
Джо
1
Не ожидал так много деталей, как ответ на мой комментарий. Я очень ценю это объяснение, спасибо!
Дан