Як я можу запустити певну команду для кожного результату пошуку?


49

Як можна запустити певну команду для кожного знайденого файлу за допомогою findкоманди? Для цього питання скажемо, що я просто хотів би видалити кожен знайдений файл find.

Відповіді:


60

Редагувати: Хоча наступна відповідь пояснює загальний випадок використання, я повинен зазначити, що видалення файлів і каталогів є особливим випадком. Замість використання -execdir rm {} \;конструкції просто використовуйте -delete, як у:

find -iname '*.txt' -delete

Це обробляє купу крайових справ, про які ви можете не замислюватися, зокрема про те, які файли замовлень та каталоги потрібно видалити, щоб не виникли помилки. Для інших випадків використання ...

Найкращий спосіб обробляти виконуючі команди результатів знаходження, як правило, використовувати різні -execпараметри для findкоманди. Зокрема, ви повинні намагатися використовувати, -execdirколи це можливо, оскільки він працює в каталозі знайденого файлу і, як правило, безпечніший (у сенсі запобігання нерозумним помилкам), ніж інші варіанти.

За -execпараметрами слідує команда, яку ви хочете виконати, {}позначаючи місце, куди повинен бути включений файл, знайдений знахідкою, і припиняється або \;запускати команду один раз для кожного файлу, або +замінювати {}список аргументів усіх збігів . Зауважте, що крапку з крапкою з комою уникнути, щоб оболонка не була зрозумілою як роздільник, що веде до нової команди.

Скажімо, ви знаходили всі текстові файли:

find -iname '*.txt' -execdir rm {} \;

Ось відповідний біт із посібника з пошуку ( man find):

   -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.  See the EXAMPLES sec-
          tion for examples of the use of the -exec option.  The specified
          command is run once for each matched file.  The command is  exe-
          cuted  in  the starting directory.   There are unavoidable secu-
          rity problems surrounding use of the -exec  action;  you  should
          use the -execdir option instead.


   -exec command {} +
          This  variant  of the -exec action runs the specified command on
          the selected files, but the command line is built  by  appending
          each  selected file name at the end; the total number of invoca-
          tions of the command will  be  much  less  than  the  number  of
          matched  files.   The command line is built in much the same way
          that xargs builds its command lines.  Only one instance of  ‘{}’
          is  allowed  within the command.  The command is executed in the
          starting directory.


   -execdir command ;

   -execdir command {} +
          Like -exec, but the specified command is run from the  subdirec-
          tory  containing  the  matched  file,  which is not normally the
          directory in which you started find.  This a  much  more  secure
          method  for invoking commands, as it avoids race conditions dur-
          ing resolution of the paths to the matched files.  As  with  the
          -exec action, the ‘+’ form of -execdir will build a command line
          to process more than one matched file, but any given  invocation
          of command will only list files that exist in the same subdirec-
          tory.  If you use this option, you must ensure that  your  $PATH
          environment  variable  does  not  reference  ‘.’;  otherwise, an
          attacker can run any commands they like by leaving an  appropri-
          ately-named  file in a directory in which you will run -execdir.
          The same applies to having entries in $PATH which are  empty  or
          which are not absolute directory names.

Команда "знайти", надана Busybox, не підтримує параметр -execdir, отже, можливо, буде потрібно використовувати один із методів pipe / xargs, згаданий нижче.
MikeW

9

Альтернативою є передача виводу та розбір його з подальшими командами. Єдиний безпечний спосіб зробити це - скористатися -print0параметром, який говорить findпро використання нульового символу як роздільника результатів. Команди прийому повинні мати здатність розпізнавати введений з нулем вхід. Приклад:

find /home/phunehehe -iregex '.*\.png$' -print0 | xargs -0 file

Зауважте, що -0параметр вказує xargsна трактування введення як нульового обмеження.


Ви можете мати -execбільше файлів, якщо +замість них закінчите ;. Дивіться відповідь калеба.
Кевін

@Kevin ви праві, я оновив відповідь.
phunehehe

3

Find має вбудовану команду delete, якщо це все, що вам потрібно зробити.

find . -name "*.txt" -delete

Будь-який знайдений .txt файл буде видалений за допомогою команди вище.


2

Я шукав відповідь на це, і натрапив на цю нитку. Відповіді дали мені і уявлення про те, як я міг цього досягти. Припустимо, ви хочете знайти mediainfoвсі файли JPEG

Це додається mediainfo "на початку та "в кінці кожного відповідного файлу (Щоб максимально уникнути спеціальних символів), покладіть його до сценарію та запустіть сценарій:

find . -name *.jpg | sed -e 's/^/mediainfo "/g;' | sed -e 's/$/"/g;' > foo.sh && sh foo.sh

Якщо ви переживаєте, що щось може піти не так, ви можете пропустити перенаправлення виводу у файл і просто побачити результат у терміналі перед запуском сценарію.


1

Ви можете досягти цього за допомогою xargsкоманди. xargsпо суті, виконує команду один раз для кожної інструкції її стандартного вводу. Отже, якщо вам потрібно, наприклад, видалити всі .jpgфайли в каталозі, швидкий шлях у командному рядку:

$ find ./ -name "*.jpg" | xargs rm 

Ви також можете скористатися функцією backtick (над кнопкою Tab), щоб зробити це (зауважте, що це символ зворотного котирування, а не єдиний символ цитування):

$ rm `find ./ -name "*.jpg"`

Зауважте, що завдяки способу xargsта оболонкам обробляють свій вхід, метод xargs працює лише у тому випадку, якщо жодне із залучених імен файлів та імен каталогів не містить пробілу чи будь-якого з них \"'; метод зворотного котирування працює лише в тому випадку, якщо жодне із залучених імен файлів та імен каталогів не містить пробілу або будь-якого з \[?*.


3
Обидва ці способи потенційно є дуже небезпечними, особливо метод "бетінг". Існують численні потенційні проблеми з невідкритими символами в іменах файлів, які можуть призвести до порушення цих методів.
Калеб

1
Я бачу вашу думку, але ці команди також можна використовувати разом з іншими інструментами, крім пошуку, тому я думаю, що тут варто згадати.
IG83

Вони, можливо, варто згадати, але коли їх не використовувати, важливо вказати. Питання ОП тут спеціально попросило вирішити результат find, який, -execяк правило, є кращим рішенням. Якщо ви хочете вказати їх як альтернативні, принаймні поясніть, як використовувати find -print0 | xargs -0для безпечної обробки перерв імен файлів, і детальніше поясніть, коли слід бути обережними щодо зворотних посилань.
Калеб

1
Ласкаво просимо на сайт, я бачу, це ваша перша відповідь. Вибачте, що стрибаю через це. Важливо навчити людей випереджати такі питання, щоб вони не робили помилок, які важко зловити пізніше, але я все ще пам’ятаю дні, коли я також не розумів, чому це така велика проблема, тому, будь ласка, не Не приймайте виправлення як особисте.
Калеб

3
Дякую за прийом! Звичайно, немає ніяких важких почуттів, ви, звичайно, праві в тому, що -exec - це відповідний спосіб впоратися з цим. Я справді починаю бачити, наскільки ця платформа чудова, ви
дізнаєтесь
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.