Відповідь Муру підходить і добре підходить для випадків, коли ми хочемо щось надрукувати, якщо файл знайдений. У загальному випадку, коли ми хочемо виконати зовнішню команду, наприклад echo
, ми можемо використовувати -exec
прапор.
$ find . -name 'xac' -exec echo "I found " {} \; -quit
I found ./xac
{}
Частина проходить ім'я файлу в команді між -exec
і в \;
якості аргументів. Зверніть увагу на \
попереднє ;
- це заважає помилковій інтерпретації оболонки ; в крапці з комою, яка закривається оболонкою, означає кінець команди, але, коли вона переходить з косою косою, оболонка буде розглядати її як текст, що переноситься на find
команду, і знаходить команду, яка служить для закриття -exec
аргументів прапора.
Для побудови умовних умов if found do this; else do that
подібного роду ми могли б використовувати підменю команд $()
та test
команду (ака [
):
$ [ "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
Звертаючись до коментаря Дана
Ден у коментарях запитав:
Чи не відлуння "Я знайшов {}" краще, ніж відлуння "Я знайшов" {}? Можливо, для відлуння це добре, але якщо хтось скопіює команду та замінить ехо на іншу команду, у них можуть виникнути проблеми
Давайте розберемося спочатку з проблемою. Зазвичай в оболонках є поняття розділення слів, що означає, що нерозмінені змінні та позиційні параметри будуть розширені та розглядаються як окремі елементи. Наприклад, якщо у вас є змінна 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
. Я щось пропустив?