2008-10-09 23 views
6

Wiele razy muszę pracować z katalogami zawierającymi setki tysięcy plików, dopasowując tekst, zastępując i tak dalej. Jeśli pójdę standardową trasę, powiedzmyJak radzisz sobie z problemem "Zbyt wiele plików" podczas pracy w Bash?

grep foo * 

pojawia się zbyt wiele wiadomości pliki błędzie, więc kończy się robi

for i in *; do grep foo $i; done 

lub

find ../path/ | xargs -I{} grep foo "{}" 

Ale to mniej niż optymalny (utwórz nowy proces grep dla każdego pliku).

To wygląda bardziej na ograniczenie rozmiaru argumentów, które mogą otrzymać programy, ponieważ * w pętli for działa poprawnie. Ale w każdym razie, jaki jest właściwy sposób, aby sobie z tym poradzić?

PS: Nie mów mi, żebym zrobił grep -r zamiast tego, wiem o tym, myślę o narzędziach, które nie mają opcji rekursywnej.

Odpowiedz

8

W nowszych wersjach findutils, znaleźć można zrobić praca xargs (w tym zachowania glomming tak, że tylko tyle, ile potrzeba grep procesy są stosowane):

find ../path -exec grep foo '{}' + 

Zastosowanie + zamiast ; jako ostatni argument wyzwala to zachowanie.

+0

Świetna rada! Nigdy nie wiedziałem o opcji "+". – mhawke

4

xargs nie uruchamia nowego procesu dla każdego pliku. Gromadzi razem argumenty. Spójrz na opcję -n dla xargs - kontroluje liczbę argumentów przekazywanych do każdego wykonania pod-polecenia.

+0

Jak wspomniał Ry4an, użycie xargs -I włącza dozowanie. – ephemient

+0

Awans do 'xargs -n' –

0

Nie widzę że

for i in *; do 
    grep foo $i 
done 

będzie działać, ponieważ myślałem, że „zbyt wiele plików” było ograniczenie powłoki, a więc to nie dla pętli for również.

Mimo, że ja zawsze niech xargs zrobić chrząknięcie-pracę dzieląc listę argumentów do opanowania bitów tak:

find ../path/ | xargs grep foo 

To nie rozpocznie się proces w jednym pliku, ale w grupie plików.

+0

Nie, ograniczenie" zbyt wielu plików "jest spowodowane tym, że długość argumentów wykonywanego programu jest ograniczona. "for i in *" nigdy nie opuszcza bieżącej powłoki, aby wykonać inny program, więc nie może przekroczyć tego ograniczenia. – ephemient

+0

Echo i rozwinięcie powyższego komentarza - jest to limit łączonej zmiennej środowiskowej i przestrzeni argv, wspólnej dla każdego wywołania procesu, a nie ograniczenia powłoki. Przydziały pamięci globalnych ekspansji pochodzą ze sterty - nie podlegają temu - dopóki i dopóki nie spróbujesz umieścić ich wyników w linii poleceń zewnętrznego polecenia lub zmiennej środowiskowej (zmienne powłoki nie eksportowane do środowiska są nadal tylko sterty, a więc dobrze). –

6

Jeśli istnieje ryzyko nazw zawierających spacje, należy pamiętać, aby używać -print0 flagę znaleźć wraz z flagą do xargs -0:

find . -print0 | xargs -0 grep -H foo 
+0

Zwykle używam 'xargs -d '\ n'' używając newlines jako separatorów, ponieważ domyślnie znajduję ścieżki wyjściowe oddzielone od siebie liniami. – ephemient

+0

@ephemient, to niebezpieczne, ponieważ systemy plików POSIX pozwalają na nowe linie w nazwach plików. –

+0

Niebezpieczne w jaki sposób? Tak, istnieje możliwość, że grep zawiedzie w niektórych nazwach plików, ale chyba że w samej grep jest luka w zabezpieczeniach, jak to jest niebezpieczne? – JesperE

0

Cóż, miałem te same problemy, ale wydaje mi się, że wszystko, co wymyśliłem, zostało już wspomniane. Przeważnie miał dwa problemy. Tworzenie globów jest kosztowne, ponieważ ls na milionie katalogów plików trwa wiecznie (ponad 20 minut na jednym z moich serwerów), a ls * na miliony katalogów plików trwa wiecznie i kończy się niepowodzeniem z błędem "lista argumentów za długo".

find /some -type f -exec some command {} \; 

wydaje się pomagać z obydwoma problemami. Ponadto, jeśli potrzebujesz wykonać bardziej złożone operacje na tych plikach, możesz rozważyć skryptowanie swoich rzeczy w wielu wątkach. Oto podkład Pythona dla skryptowych rzeczy CLI. http://www.ibm.com/developerworks/aix/library/au-pythocli/?ca=dgr-lnxw06pythonunixtool&S_TACT=105AGX59&S_CMP=GR

+0

Używanie find -exec grep foo ';' ma taki sam problem jak oryginalne rozwiązanie, ponieważ uruchamia pojedynczą instancję grep dla każdego pliku. –