2008-11-20 14 views

Odpowiedz

109

Zadanie interpretacji kreską jako instrukcja do uruchomienia wielu procesów i rury wyjście jednego procesu na wejście inny proces to odpowiedzialność powłoki (/ bin/sh lub odpowiednik).

W przykładzie można albo zdecydować się na korzystanie z górną powłokę poziom wykonać orurowanie tak:

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

Pod względem wydajności wynika to koszty jednorazowe wywołanie znaleźć liczne inwokacje o zcat, a jeden inwokacja agrep.

Spowoduje to utworzenie tylko jednego procesu agrep, który przetwarzałby wszystkie dane wyjściowe wygenerowane przez liczne wywołania zcat.

Jeśli chcesz z jakiegoś powodu chciał powołać agrep wiele razy, można zrobić:

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

ten konstruuje listę poleceń z użyciem rur do wykonania, a następnie wysyła je do nowej powłoce, aby rzeczywiście być wykonywane . (Pominięcie ostatecznego "| sh" jest dobrym sposobem na debugowanie lub wykonywanie suchych przebiegów linii poleceń takich jak ta.)

Pod względem wydajności ten wynik kosztuje jedno wywołanie znalezienia, jedno wywołanie sh, liczne wywołania zcat i liczne inwokacje agrep.

Najbardziej efektywnym rozwiązaniem pod względem liczby wywołań polecenia jest sugestia od Pawła Tomblin:

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

... który kosztuje jedno wywołanie znaleźć, jedno wywołanie xargs, kilka wezwań o zcat i jedno wezwanie agrep.

+1

Kolejną zaletą xargs byłoby to, że można go przyspieszyć nowoczesnym procesorem wielordzeniowym jeszcze bardziej, używając przełącznika -P (-P 0). – flolo

+0

Tak, opcja -P jest rzeczywiście dobrym sposobem na przyspieszenie wykonywania w ogóle. Niestety, istnieje ryzyko, że wynik równoległych procesów zcat zostanie podłączony do przeplecionego agrepu, co wpłynie na wynik. Efekt ten można wykazać za pomocą: echo -e "1 \ n2" | xargs -P 0 -n 1 tak | uniq –

+0

@Adam, wprowadziłem sugerowaną zmianę. –

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

Mając nadzieję na uniknięcie -Print i xargs ze względów wydajności. Może to jest mój problem: find nie może obsłużyć wypisanych poleceń przez -exec – someguy

+0

Nie działa to w przypadku plików z spacjami w ich nazwach; naprawić, zamień -print z -print0 i dodaj opcję -0 do xargs –

+2

@someguy - Wha? Unikanie xargs ze względów wydajnościowych? Wywołanie jednej instancji zcat i przekazanie jej listy wielu plików jest * znacznie * wydajniejsze niż wykonanie nowej instancji dla każdego znalezionego pliku. –

190

rozwiązanie jest proste: wykonać przez sh

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

To, co OP próbował osiągnąć, można spotkać z powyższymi sugestiami, ale to właśnie on odpowiada na zadane pytanie. Istnieją powody, aby zrobić to w ten sposób - exec jest o wiele potężniejszy niż działanie na plikach zwracanych przez find, szczególnie w połączeniu z testem. Na przykład: znajdź geda-gaf/typ d -exec bash -c 'DIR = {}; [[$ (znajdź $ DIR -maxdepth 1 | xargs grep -i spice | wc -l) -ge 5]] && echo $ DIR '\; Zwróci wszystkie katalogi w ścieżce wyszukiwania, które zawierają więcej niż 5 wierszy łącznie spośród wszystkich plików w tym katalogu zawierających słowo spice. – swarfrat

+2

Najlepsza odpowiedź. Pomijanie całego wyniku (jak sugerują inne odpowiedzi) nie jest tym samym, co grep dla każdego pliku. Wskazówka: zamiast sh możesz użyć dowolnej innej powłoki (próbowałem tego z bash i działa poprawnie). – pagliuca

+1

Upewnij się, że nie przeoczyłeś opcji '-c'. W przeciwnym razie pojawi się zagadkowy komunikat o błędzie "Brak takiego pliku lub katalogu". – asmaier

8

Można również podłączyć do pętli while, która może wykonywać wiele operacji na pliku znajdującym się pod adresem find. Więc tutaj jest jeden dla patrząc w jar archiwum dla danego pliku klasy java w folderze z dużej dystrybucji w jar plików

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

kluczowym punktem jest, że pętla while zawiera wiele poleceń odwołujące przekazany w nazwie pliku oddzielone średnik i te polecenia mogą zawierać potoki. Tak więc w tym przykładzie wywołuję echo nazwy pasującego pliku, a następnie wyświetlam zawartość filtrowania archiwum dla danej nazwy klasy. Wyjście wygląda następująco:

/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/obserserv/list/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

w mojej powłoce bash (xubuntu10.04/xfce) tak naprawdę czyni dopasowaną nazwę klasy pogrubioną, ponieważ fgrep podświetla dopasowany ciąg; dzięki temu można z łatwością zeskanować listę setek znalezionych plików jar i łatwo zobaczyć wszystkie dopasowania.

na oknach można zrobić to samo z:

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

Zauważ, że w oknach, które na polecenie jest separator „&” nie „;” i że '@' tłumi echo polecenia, aby dać czysty wynik, tak jak wynik linuksa znajdujący się powyżej; chociaż findstr nie jest pogrubionym pasującym ciągiem, więc musisz przyjrzeć się bliżej wynikowi, aby zobaczyć dopasowaną nazwę klasy. Okazuje się, że okna „dla” polecenia wie sporo sztuczek, takich jak zapętlenie poprzez pliki tekstowe ...

cieszyć

Powiązane problemy