Jak potokować listę plików zwróconych przez komendę find do cat, aby wyświetlić wszystkie pliki

204

Robię finda następnie otrzymuję listę plików. Jak przesłać potokiem do innego narzędzia, takiego jak cat(aby cat wyświetlał zawartość wszystkich tych plików) i zasadniczo potrzebował grepczegoś z tych plików.

Devang Kamdar
źródło

Odpowiedzi:

340
  1. Przesyłanie potokowe do innego procesu (chociaż to NIE osiągnie tego, o czym mówiłeś, że próbujesz zrobić):

    command1 | command2
    

    Spowoduje to wysłanie danych wyjściowych polecenia 1 jako danych wejściowych polecenia 2

  2. -execna find(to zrobi to, co chcesz zrobić - ale jest specyficzne dla find)

    find . -name '*.foo' -exec cat {} \;
    

    (Wszystko pomiędzy findi -execsą predykatami znajdowania, których już używałeś. {}Zastąpi konkretny plik znaleziony w poleceniu ( cat {}w tym przypadku); \;ma to zakończyć -execpolecenie).

  3. wysyła dane wyjściowe jednego procesu jako argumenty wiersza poleceń do innego procesu

    command2 `command1`
    

    na przykład:

    cat `find . -name '*.foo' -print`
    

    (Zauważ, że są to TYLNE CYTATY, a nie regularne cudzysłowy (pod tyldą ~ na mojej klawiaturze).) Spowoduje to wysłanie wyniku command1do command2jako argumentów wiersza poleceń. Pamiętaj jednak, że nazwy plików zawierające spacje (znaki nowej linii itp.) Zostaną podzielone na osobne argumenty.

kenj0418
źródło
2
kot find -name '*.foo' -printpracował dla mnie świetnie ... Dzięki
Devang Kamdar
Cytaty wsteczne działają świetnie i są bardziej uogólnione, możesz użyć tego również do przechwycenia listy plików z pliku.
Hazok
11
Zauważ, że współczesne wersje findpozwalają pisać:, find . -name '*.foo' -exec cat {} +gdzie +wskazuje, że findpowinno grupować tyle wygodnych nazw plików w jedno wywołanie polecenia. Jest to bardzo przydatne (zajmuje się spacjami itp. W nazwach plików bez uciekania się do -print0i xargs -0).
Jonathan Leffler
18
Nie wspomniano:find . -name '*.foo' | xargs cat
gulasz Kwadrat
3
Aby dodać odpowiedź @stewSquared: Aby znaleźć wszystkie wiersze w plikach zawierających określony ciąg znaków, wykonajfind . -name '*.foo' | xargs cat | grep string
Bim
84

Nowoczesna wersja

POSIX 2008 dodał +znacznik, findco oznacza, że ​​teraz automatycznie grupuje tyle plików, ile jest to rozsądne, w wykonanie jednego polecenia, podobnie jak xargsrobi, ale ma wiele zalet:

  1. Nie musisz się martwić o nieparzyste znaki w nazwach plików.
  2. Nie musisz się martwić, że polecenie zostanie wywołane z zerowymi nazwami plików.

Problem z nazwą pliku jest problemem xargsbez -0opcji, a problem „uruchom nawet przy zerowych nazwach plików” jest problemem z -0opcją lub bez - ale GNU xargsma opcję -rlub --no-run-if-empty, aby temu zapobiec. Ponadto notacja ta ogranicza liczbę procesów, nie dlatego, że prawdopodobnie zmierzysz różnicę wydajności. Dlatego można rozsądnie napisać:

find . -exec grep something {} +

Wersja klasyczna

find . -print | xargs grep something

Jeśli jesteś na Linuksie lub mają GNU findi xargspoleceń, a następnie skorzystać -print0z finda -0z xargsw nazwach plików uchwyt zawierających spacje i inne znaki odd-ball.

find . -print0 | xargs -0 grep something

Poprawianie wyników z grep

Jeśli nie chcesz nazw plików (tylko tekstu), dodaj odpowiednią opcję grep(zwykle w -hcelu pominięcia „nagłówków”). Aby absolutnie zagwarantować, że nazwa pliku jest drukowana przez grep(nawet jeśli znaleziono tylko jeden plik lub ostatnie wywołanie grepma tylko 1 nazwę pliku), następnie dodaj /dev/nulldo xargswiersza poleceń, aby zawsze były co najmniej dwie nazwy plików.

Jonathan Leffler
źródło
Dla tych zdezorientowanych jak ja, zwróć uwagę, że w ten sposób najpierw podasz wszystkie wyniki find, a następnie dane wyjściowe xargs grep something.
Eric Hu
3
@EricHu: Widzę, że jesteś zdezorientowany, ale nie robi tego, co mówisz, robi, przynajmniej nie na żadnym znanym mi systemie opartym na Uniksie. Wyjście findjest przesyłane do standardowego wejścia xargs. xargsProgram odczytuje swoje standardowe wejście, dzieląc wejście w białej przestrzeni (spacje, znaki nowej linii, zakładki, itp) i dodaje kilka słów do komendy grep somethingi wykonuje wiersza poleceń. xargsnastępnie kontynuuje czytanie danych wejściowych i wykonywanie poleceń, dopóki nie zabraknie danych wejściowych. xargsuruchamia greppolecenie tak często, jak jest to konieczne dla danych wejściowych, które zostały podane (z findtego przykładu).
Jonathan Leffler,
Ach mój błąd, to używa grep do wyszukiwania w każdym dopasowanym pliku. Chciałem po prostu filtrować wyjście find za pomocą grep
Eric Hu
1
Błędy przechodzą w błąd standardowy (deskryptor pliku 2) we wszystkich dobrze zachowanych poleceniach. Przekierowanie stderr do /dev/nullutraty komunikatów o błędach.
Jonathan Leffler
1
Ma to również tę zaletę, że działa lepiej ze spacjami w ścieżce pliku. Nawet „sed'ing” ”->„ \ ”łamie to z„ ale z
xargsem
36

Istnieje kilka sposobów przekazywania listy plików zwróconych przez findpolecenie do catpolecenia, chociaż technicznie nie wszystkie z nich używają potokowania i żaden z nich nie jest bezpośrednio potokowany bezpośrednio cat.

  1. Najprostszym jest użycie backticks ( `):

    cat `find [whatever]`
    

    To pobiera dane wyjściowe findi skutecznie umieszcza je w wierszu poleceń cat. Nie działa to dobrze, jeśli findma zbyt dużo danych wyjściowych (więcej niż może zmieścić się w wierszu poleceń) lub jeśli dane wyjściowe zawierają znaki specjalne (takie jak spacje).

  2. W niektórych powłokach, w tym bash, można użyć $()zamiast backticks:

    cat $(find [whatever])
    

    Jest to mniej przenośne, ale można je zagnieździć. Poza tym ma prawie takie same zastrzeżenia jak backtyki.

  3. Ponieważ uruchamianie innych poleceń na tym, co znaleziono, jest powszechnym zastosowaniem find, find ma -execakcję, która wykonuje polecenie dla każdego znalezionego pliku:

    find [whatever] -exec cat {} \;
    

    {}Jest symbolem zastępczym dla nazwy pliku, a \;znaki końca polecenia (jest to możliwe, aby po inne działania -exec).

    Będzie on uruchamiany catraz dla każdego pliku, zamiast uruchamiać jedną instancję, catprzekazując mu wiele nazw plików, co może być nieefektywne i może nie mieć pożądanego zachowania w przypadku niektórych poleceń (choć jest w porządku cat). Składnia jest również niewygodna w pisaniu - musisz uciec od średnika, ponieważ średnik jest szczególny dla powłoki!

  4. Niektóre wersje find(zwłaszcza w wersji GNU) pozwalają zastąpić ;z +do użytku -execów trybie dopisywania do uruchomienia mniej przypadków” cat:

    find [whatever] -exec cat {} +
    

    Spowoduje to przekazanie wielu nazw plików do każdego wywołania cat, co może być bardziej wydajne.

    Pamiętaj jednak, że nie można zagwarantować użycia pojedynczego wywołania. Jeśli linia poleceń byłaby zbyt długa, argumenty byłyby rozłożone na wiele wywołań cat. Na catto chyba nie jest to nic wielkiego, ale dla niektórych innych poleceń może się to zmienić zachowanie w niepożądany sposób. W systemach Linux limit długości wiersza poleceń jest dość duży, więc podział na wiele wywołań jest dość rzadki w porównaniu do niektórych innych systemów operacyjnych.

  5. Klasyczne / przenośne podejście polega na użyciu xargs:

    find [whatever] | xargs cat
    

    xargsuruchamia podane polecenie ( catw tym przypadku) i dodaje argumenty na podstawie tego, co czyta ze standardowego wejścia. Podobnie jak w -execprzypadku +, w razie potrzeby spowoduje to uszkodzenie wiersza poleceń. Oznacza to, że jeśli findwytworzy zbyt dużo danych wyjściowych, będzie działać catwiele razy. Jak wspomniano we -execwcześniejszej części, istnieje kilka poleceń, w których podział może powodować różne zachowania. Zauważ, że użycie xargstego typu powoduje problemy ze spacjami w nazwach plików, ponieważ xargsużywa tylko białych znaków jako separatora.

  6. Najbardziej niezawodna, przenośna i wydajna metoda wykorzystuje również xargs:

    find [whatever] -print0 | xargs -0 cat
    

    -print0Flaga mówi findużywać \0(znak null) separatory pomiędzy nazwami plików, a -0flaga mówi xargssię spodziewać tych \0ograniczników. To zachowanie jest prawie identyczne jak w podejściu -exec... +, ale jest bardziej przenośne (ale niestety bardziej szczegółowe).

Laurence Gonsalves
źródło
Metoda wsteczna jest świetna, ponieważ działa również dla innych poleceń, takich jak ls.
Martin Braun
@Martin Braun przy użyciu $()Działa również z poleceniami innymi niż find .
Laurence Gonsalves
Dzięki, dobrze wiedzieć, trochę przestałem czytać po (1), ponieważ służy to moim potrzebom, ponieważ nie mam do czynienia ze znakami specjalnymi, takimi jak spacje i tym podobne.
Martin Braun
9

Aby to osiągnąć (używając bash), zrobiłbym co następuje:

cat $(find . -name '*.foo')

Jest to znane jako „podstawianie poleceń” i domyślnie usuwa wiersz, co jest naprawdę wygodne!

więcej informacji tutaj

Stphane
źródło
6

Brzmi jak praca dla skryptu powłoki:

for file in 'find -name *.xml'
do
   grep 'hello' file
done

czy jakoś tak

Gandalf
źródło
2
To ważna, choć niekoniecznie optymalna odpowiedź na pytanie.
Jonathan Leffler
1
... tak, ale świetnie, jeśli chcesz mieć także jeden duży plik z nazwami plików.
ʍǝɥʇɐɯ
1
Najbardziej to lubię. Blok pętli taki jak ten pozostawia miejsce na inne rzeczy.
kakyo
4

Oto mój sposób na znalezienie nazw plików zawierających treści, które mnie interesują, tylko jedną linię bash, która ładnie obsługuje spacje w nazwach plików:

find . -name \*.xml | while read i; do grep '<?xml' "$i" >/dev/null; [ $? == 0 ] && echo $i; done
Greg
źródło
3

Używam czegoś takiego:

find . -name <filename> -print0 | xargs -0 cat | grep <word2search4>

-print0Argumenty „ ” argument „find” i „ -0” argumenty „xargs” są potrzebne do poprawnej obsługi białych znaków w ścieżkach / nazwach plików.

ekinak
źródło
2

Polecenie find ma argument -exec, którego możesz użyć do takich rzeczy, możesz po prostu wykonać grep bezpośrednio za jego pomocą.

Na przykład ( stąd inne dobre przykłady na tej stronie ):

find . -exec grep "www.athabasca" '{}' \; -print 
Chad Birch
źródło
2

Oto mój strzał do ogólnego użytku:

grep YOURSTRING `find .`

Wyświetli nazwę pliku

zakki
źródło
2

W bash odpowiednie będą:

find /dir -type f -print0 | xargs -0i cat {} | grep whatever

To znajdzie wszystkie pliki w /dirkatalogu i bezpiecznie potokuje nazwy plików xargs, które bezpiecznie będą prowadzić grep.

Pomijanie xargsnie jest dobrym pomysłem, jeśli masz wiele tysięcy plików /dir; catulegnie awarii z powodu nadmiernej długości listy argumentów. xargszałatwi to dla ciebie.

-print0Argument findzazębia się z -0argumentem, aby xargsprawidłowo obsługiwać nazwy plików ze spacjami. -iArgument xargspozwala wstawić nazwę pliku, gdzie wymagane w catwierszu poleceń. Nawiasy zastępuje się nazwą pliku wprowadzoną do catpolecenia z find.

McClain Looney
źródło
0

To działa dla mnie

find _CACHE_* | while read line; do
    cat "$line" | grep "something"
done
Steven Penny
źródło
0

Użyj ggrep .

ggrep -H -R -I "mysearchstring" *

aby wyszukać plik w systemie uniksowym zawierający tekst znajdujący się w bieżącym katalogu lub podkatalogu

Cofnij
źródło
0

Spowoduje to wydrukowanie rekursywnie nazwy i zawartości tylko plików.

find . -type f -printf '\n\n%p:\n' -exec cat {} \;

Edycja (ulepszona wersja): Spowoduje to wydrukowanie rekursywnie nazwy i zawartości plików tekstowych (ascii).

find . -type f -exec grep -Iq . {} \; -print | xargs awk 'FNR==1{print FILENAME ":" $0; }'

Jeszcze jedna próba

find . -type f -exec grep -Iq . {} \; -printf "\n%p:" -exec cat {} \;
Prashant Adlinge
źródło
-1

Czy próbujesz znaleźć tekst w plikach? Możesz po prostu użyć do tego grep ...

grep searchterm *
Scott Anderson
źródło
-1

Aby wyświetlić i zobaczyć zawartość wszystkich plików abc.def na serwerze w katalogach / ghi i / jkl

find /ghi /jkl -type f -name abc.def 2> /dev/null -exec ls {} \; -exec cat {} \;

Aby wyświetlić listę plików abc.def, które skomentowały wpisy i wyświetlić, zobacz te wpisy w katalogach / ghi i / jkl

find /ghi /jkl -type f -name abc.def 2> /dev/null -exec grep -H ^# {} \;
Sharjeel
źródło