Як включити трубу | у моїй команді linux find -exec?


220

Це не працює. Чи можна це зробити в пошуку? Або мені потрібно xargs?

find -name 'file_*' -follow -type f -exec zcat {} \| agrep -dEOE 'grep' \;

Відповіді:


145

Завдання інтерпретації символу труби як інструкції запускати декілька процесів та передавати вихід одного процесу на вхід іншого процесу - це відповідальність оболонки (/ bin / sh або еквівалент).

У вашому прикладі ви можете або використовувати оболонку верхнього рівня, щоб виконати трубопроводи так:

find -name 'file_*' -follow -type f -exec zcat {} \; | agrep -dEOE 'grep'

З точки зору ефективності цей результат коштує одного виклику знаходження, численних викликів zcat та одного виклику agrep.

Це призвело б до породження лише одного узгодженого процесу, який обробив би всі результати, отримані численними викликами zcat.

Якщо ви з якоїсь причини хочете кілька разів викликати agrep, ви можете зробити:

find . -name 'file_*' -follow -type f \
    -printf "zcat %p | agrep -dEOE 'grep'\n" | sh

Це створює перелік команд, які використовують труби для виконання, а потім надсилає їх у новий оболонку для фактичного виконання. (Пропуск остаточного "| sh" - хороший спосіб налагодження або виконання сухих запусків командних рядків типу цього.)

З точки зору ефективності цей результат коштує одного виклику знаходження, одного виклику sh, численних викликів zcat та численних викликів agrep.

Найбільш ефективним рішенням щодо кількості викликів команд є пропозиція Пола Томбліна:

find . -name "file_*" -follow -type f -print0 | xargs -0 zcat | agrep -dEOE 'grep'

... що коштує одного виклику знаходження, одного виклику xargs, декількох викликів zcat та одного виклику agrep.


1
Ще однією перевагою xargs було б те, що ви можете прискорити його за допомогою сучасного багатоядерного процесора ще більше, використовуючи перемикач -P (-P 0).
flolo

Так, -P swich - це справді хороший спосіб прискорити виконання в цілому. На жаль, ви ризикуєте вивести паралельні процеси zcat в трубопровід, переплетений, що вплине на результат. Цей ефект можна продемонструвати, використовуючи: echo -e "1 \ n2" | xargs -P 0 -n 1 так | uniq
Rolf W. Rasmussen

@Adam, я вніс запропоновані вами зміни.
Пол Томблін

для яких можна встановити чудову команду xjobs (спочатку від Solaris)
sehe

4
Більш проста та загальна відповідь - на stackoverflow.com/a/21825690/42973 : -exec sh -c "… | … " \;.
Ерік О Лебігот,

278

рішення просте: виконати через sh

... -exec sh -c "zcat {} | agrep -dEOE 'grep' " \;

17
Те, що намагалася досягти ОП, можна зустріти з наведеними вище пропозиціями, але саме ця відповідь відповідає на поставлене питання. Є причини зробити це таким чином - exec набагато потужніше, ніж просто працювати з файлами, поверненими знахідкою, особливо в поєднанні з тестом. Наприклад: знайти geda-gaf / -type d -exec bash -c 'DIR = {}; [[$ (знайти $ DIR -maxdepth 1 | xargs grep -i спеція | wc -l) -ge 5]] && відлуння $ DIR '\; Поверне всі каталоги на шляху пошуку, які містять більше 5 рядків серед усіх файлів у цьому каталозі, що містять слово spice
swarfrat

3
Найкраща відповідь. Обрізання всього виводу (як підказують інші відповіді) - це не те, що знімати кожен файл. Порада: замість sh, ви можете використовувати будь-яку іншу оболонку, яку ви хочете (я спробував це з bash, і він працює нормально).
pagliuca

1
Не забудьте вибрати -cваріант. Інакше ви отримаєте дивовижне No such file or directoryповідомлення про помилку.
asmaier

ось чудова заміна ps, яка використовує пошук із трубопроводом всередині оболонки exec'd: / usr / bin / find / proc -mindepth 1 -maxdepth 1 -тип d -regex '. * / [0-9] +' - print -exec bash -c "кішка {} / cmdline | tr '\\ 0' ''; ехо" \;
parity3

1
Приклад пошуку файлів та перейменування їх sed за допомогою регулярного вираження find -type f -name '*.mdds' -exec sh -c "echo {} | sed -e 's/_[0-9]\+//g' | xargs mv {}" \;
Rostfrei

16
find . -name "file_*" -follow -type f -print0 | xargs -0 zcat | agrep -dEOE 'grep'

Сподіваючись уникнути -принта та xargs з міркувань ефективності. Можливо, це справді моя проблема: знайти не вдається обробити трубопровідні команди через -exec
someguy

Це не працює з файлами з пробілами в їх іменах; щоб виправити, замінити -print на -print0 та додати параметр -0 до xargs
Адам Розенфілд

2
@someguy - Що? Уникаючи xargs з міркувань ефективності? Викликати один екземпляр zcat та передавати йому список декількох файлів набагато ефективніше, ніж виконувати новий екземпляр його для кожного знайденого файлу.
Шерм Пендлі

@Adam - я вніс запропоновані вами зміни. У 99% випадків, коли я займаюся знахідкою, це в моїх каталогах вихідного коду, і жоден з файлів там не має пробілів, тому я не турбуюся з print0. Тепер, з мого каталогу документів, з іншого боку, я пам'ятаю print0.
Пол Томблін

10

Ви також можете передати whileцикл, який може робити кілька дій над файлом, який findзнаходиться. Отже, ось один для пошуку в jarархівах певного файлу класу java у папці з великим дистрибутивом jarфайлів

find /usr/lib/eclipse/plugins -type f -name \*.jar | while read jar; do echo $jar; jar tf $jar | fgrep IObservableList ; done

Ключовим моментом є те, що while цикл містить кілька команд, що посилаються на передане ім'я файлу, розділене крапкою з комою, і ці команди можуть включати в себе труби. Тож у цьому прикладі я повторюю ім’я відповідного файла, а потім перелічую те, що знаходиться в фільтрації архіву для даного імені класу. Вихід виглядає так:

/usr/lib/eclipse/plugins/org.eclipse.core.contenttype.source_3.4.1.R35x_v20090826-0451.jar /usr/lib/eclipse/plugins/org.eclipse.core.databinding.observable_1.2.0.M20090902-0800 .jar org / eclipse / core / databinding / спостерігається / список / IObservableList .class /usr/lib/eclipse/plugins/org.eclipse.search.source_3.5.1.r351_v20090708-0800.jar / usr / lib / eclipse / plugins / org.eclipse.jdt.apt.core.source_3.3.202.R35x_v20091130-2300.jar /usr/lib/eclipse/plugins/org.eclipse.cvs.source_1.0.400.v201002111343.jar / usr / lib / eclipse / plugins / org.eclipse.help.appserver_3.1.400.v20090429_1800.jar

в моїй баш-оболонці (xubuntu10.04 / xfce) вона дійсно робить зіставлене ім’я класу жирним, як fgrepпідкреслює відповідність рядка; це дозволяє дуже легко просканувати список сотень jarфайлів, які шукали, і легко переглядати будь-які збіги.

у вікнах ви можете зробити те саме:

for /R %j in (*.jar) do @echo %j & @jar tf %j | findstr IObservableList

зауважте, що в Windows на цьому розділювачі команд є "& 'not'; ' і що "@" пригнічує відлуння команди, щоб дати акуратний висновок так само, як висновок Linux знайти вище; хоча findstrне робимо зіставлену рядок жирною, тому вам доведеться трохи ближче подивитися на висновок, щоб побачити відповідне ім'я класу. Виявляється, команда windows 'for' знає досить багато хитрощів, таких як прокручування текстових файлів ...

насолоджуватися


2

Я виявив, що найкраще працює команда string shell (sh -c), наприклад:

find -name 'file_*' -follow -type f -exec bash -c "zcat \"{}\" | agrep -dEOE 'grep'" \;

0

Якщо ви шукаєте просту альтернативу, це можна зробити за допомогою циклу:

for i in $(find -name 'file_*' -follow -type f);do zcat $i | agrep -dEOE 'grep');done

або, більш загальну та просту для розуміння форму:

for i in $(YOUR_FIND_COMMAND);do YOUR_EXEC_COMMAND_AND_PIPES );done

і замініть будь-яку {} на $ i в YOUR_EXEC_COMMAND_AND_PIPES

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