Robię find
a 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ł grep
czegoś z tych plików.
Robię find
a 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ł grep
czegoś z tych plików.
Odpowiedzi:
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
-exec
na find
(to zrobi to, co chcesz zrobić - ale jest specyficzne dla find
)
find . -name '*.foo' -exec cat {} \;
(Wszystko pomiędzy find
i -exec
są predykatami znajdowania, których już używałeś. {}
Zastąpi konkretny plik znaleziony w poleceniu ( cat {}
w tym przypadku); \;
ma to zakończyć -exec
polecenie).
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 command1
do command2
jako argumentów wiersza poleceń. Pamiętaj jednak, że nazwy plików zawierające spacje (znaki nowej linii itp.) Zostaną podzielone na osobne argumenty.
find
pozwalają pisać:, find . -name '*.foo' -exec cat {} +
gdzie +
wskazuje, że find
powinno 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 -print0
i xargs -0
).
find . -name '*.foo' | xargs cat
find . -name '*.foo' | xargs cat | grep string
POSIX 2008 dodał +
znacznik, find
co oznacza, że teraz automatycznie grupuje tyle plików, ile jest to rozsądne, w wykonanie jednego polecenia, podobnie jak xargs
robi, ale ma wiele zalet:
Problem z nazwą pliku jest problemem xargs
bez -0
opcji, a problem „uruchom nawet przy zerowych nazwach plików” jest problemem z -0
opcją lub bez - ale GNU xargs
ma opcję -r
lub --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 {} +
find . -print | xargs grep something
Jeśli jesteś na Linuksie lub mają GNU find
i xargs
poleceń, a następnie skorzystać -print0
z find
a -0
z xargs
w nazwach plików uchwyt zawierających spacje i inne znaki odd-ball.
find . -print0 | xargs -0 grep something
grep
Jeśli nie chcesz nazw plików (tylko tekstu), dodaj odpowiednią opcję grep
(zwykle w -h
celu 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 grep
ma tylko 1 nazwę pliku), następnie dodaj /dev/null
do xargs
wiersza poleceń, aby zawsze były co najmniej dwie nazwy plików.
xargs grep something
.
find
jest przesyłane do standardowego wejścia xargs
. xargs
Program 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 something
i wykonuje wiersza poleceń. xargs
następnie kontynuuje czytanie danych wejściowych i wykonywanie poleceń, dopóki nie zabraknie danych wejściowych. xargs
uruchamia grep
polecenie tak często, jak jest to konieczne dla danych wejściowych, które zostały podane (z find
tego przykładu).
/dev/null
utraty komunikatów o błędach.
Istnieje kilka sposobów przekazywania listy plików zwróconych przez find
polecenie do cat
polecenia, chociaż technicznie nie wszystkie z nich używają potokowania i żaden z nich nie jest bezpośrednio potokowany bezpośrednio cat
.
Najprostszym jest użycie backticks ( `
):
cat `find [whatever]`
To pobiera dane wyjściowe find
i skutecznie umieszcza je w wierszu poleceń cat
. Nie działa to dobrze, jeśli find
ma 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).
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.
Ponieważ uruchamianie innych poleceń na tym, co znaleziono, jest powszechnym zastosowaniem find
, find ma -exec
akcję, 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 cat
raz dla każdego pliku, zamiast uruchamiać jedną instancję, cat
przekazują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!
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 cat
to 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.
Klasyczne / przenośne podejście polega na użyciu xargs
:
find [whatever] | xargs cat
xargs
uruchamia podane polecenie ( cat
w tym przypadku) i dodaje argumenty na podstawie tego, co czyta ze standardowego wejścia. Podobnie jak w -exec
przypadku +
, w razie potrzeby spowoduje to uszkodzenie wiersza poleceń. Oznacza to, że jeśli find
wytworzy zbyt dużo danych wyjściowych, będzie działać cat
wiele razy. Jak wspomniano we -exec
wcześniejszej części, istnieje kilka poleceń, w których podział może powodować różne zachowania. Zauważ, że użycie xargs
tego typu powoduje problemy ze spacjami w nazwach plików, ponieważ xargs
używa tylko białych znaków jako separatora.
Najbardziej niezawodna, przenośna i wydajna metoda wykorzystuje również xargs
:
find [whatever] -print0 | xargs -0 cat
-print0
Flaga mówi find
używać \0
(znak null) separatory pomiędzy nazwami plików, a -0
flaga mówi xargs
się spodziewać tych \0
ograniczników. To zachowanie jest prawie identyczne jak w podejściu -exec
... +
, ale jest bardziej przenośne (ale niestety bardziej szczegółowe).
ls
.
$()
Działa również z poleceniami innymi niż find
.
Brzmi jak praca dla skryptu powłoki:
for file in 'find -name *.xml'
do
grep 'hello' file
done
czy jakoś tak
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
W bash odpowiednie będą:
find /dir -type f -print0 | xargs -0i cat {} | grep whatever
To znajdzie wszystkie pliki w /dir
katalogu i bezpiecznie potokuje nazwy plików xargs
, które bezpiecznie będą prowadzić grep
.
Pomijanie xargs
nie jest dobrym pomysłem, jeśli masz wiele tysięcy plików /dir
; cat
ulegnie awarii z powodu nadmiernej długości listy argumentów. xargs
załatwi to dla ciebie.
-print0
Argument find
zazębia się z -0
argumentem, aby xargs
prawidłowo obsługiwać nazwy plików ze spacjami. -i
Argument xargs
pozwala wstawić nazwę pliku, gdzie wymagane w cat
wierszu poleceń. Nawiasy zastępuje się nazwą pliku wprowadzoną do cat
polecenia z find
.
To działa dla mnie
find _CACHE_* | while read line; do
cat "$line" | grep "something"
done
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 {} \;
Czy próbujesz znaleźć tekst w plikach? Możesz po prostu użyć do tego grep ...
grep searchterm *
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 ^# {} \;
find -name '*.foo' -print
pracował dla mnie świetnie ... Dzięki