Mam katalog (np. abc/def/efg
) Z wieloma podkatalogami (np .::) abc/def/efg/(1..300)
. Wszystkie te podkatalogi mają wspólny plik (np file.txt
.). Chcę wyszukiwać ciąg tylko w tym z file.txt
wyłączeniem innych plików. W jaki sposób mogę to zrobić?
Użyłem grep -arin "pattern" *
, ale jest bardzo powolny, jeśli mamy wiele podkatalogów i plików.
command-line
grep
find
Rajesh Keladimath
źródło
źródło
Odpowiedzi:
W katalogu nadrzędnym można było używać,
find
a następnie uruchamiaćgrep
tylko te pliki:źródło
-H
do,grep
aby w przypadkach, gdy przekazywana jest tylko jedna ścieżka, ścieżka ta jest nadal drukowana (zamiast tylko pasujących wierszy z pliku).Możesz także użyć globstar.
Budowanie
grep
poleceń za pomocąfind
, jak w odpowiedzi Zanny , jest bardzo solidnym, wszechstronnym i przenośnym sposobem na to (patrz także odpowiedź Sudodusa ). A muru opublikowało doskonałe podejście do korzystaniagrep
z--include
opcji . Ale jeśli chcesz użyć tylkogrep
polecenia i powłoki, możesz to zrobić na inny sposób - możesz sprawić, że sama powłoka wykona niezbędną rekursję :Te
-H
marki flaggrep
wyświetlić nazwę pliku, nawet jeśli tylko jeden pasujący plik zostanie znaleziony. Można przekazać-a
,-i
oraz-n
flagi (z twojego przykładzie)grep
, a także, jeśli to, co trzeba. Ale nie zaliczaj-r
lub-R
podczas korzystania z tej metody. Jest to powłoka, która powraca do katalogów w rozszerzaniu wzorca globu zawierającego**
, a niegrep
.Te instrukcje są specyficzne dla powłoki Bash. Bash jest domyślną powłoką użytkownika w Ubuntu (i większości innych systemów operacyjnych GNU / Linux), więc jeśli korzystasz z Ubuntu i nie wiesz, co to jest twoja powłoka, to prawie na pewno Bash. Chociaż popularne powłoki zwykle obsługują
**
globusy przeszukujące katalogi , nie zawsze działają w ten sam sposób. Aby uzyskać więcej informacji, zobacz Stéphane Chazelas „s doskonałą odpowiedź do wyniku ls * ls ls ** i *** na Unix.SE .Jak to działa
Włączenie opcji powłoki bash globstar powoduje, że ścieżki dopasowania zawierające separator katalogów ( ). Jest to zatem glob rekursujący katalogi. W szczególności, jak wyjaśniono:
**
/
man bash
Powinieneś być z tym ostrożny, ponieważ możesz uruchamiać polecenia, które modyfikują lub usuwają znacznie więcej plików, niż masz zamiar, zwłaszcza jeśli piszesz,
**
gdy masz zamiar pisać*
. (Jest to bezpieczne w tym poleceniu, które nie zmienia żadnych plików.)shopt -u globstar
Wyłącza opcję powłoki globstar.Istnieje kilka praktycznych różnic między globstar a
find
.find
jest znacznie bardziej wszechstronny niż globstar. Wszystko, co możesz zrobić z globstar, możesz zrobić również zfind
poleceniem. Lubię globstar i czasami jest to wygodniejsze, ale globstar nie jest ogólną alternatywą dlafind
.Powyższa metoda nie sprawdza katalogów, których nazwy zaczynają się od
.
. Czasami nie chcesz rekursować takich folderów, ale czasem tak.Podobnie jak w przypadku zwykłego globu, powłoka buduje listę wszystkich pasujących ścieżek i przekazuje je jako argumenty do polecenia (
grep
) zamiast samego globu. Jeśli masz tak wiele plików o nazwie,file.txt
że wynikowe polecenie byłoby zbyt długie, aby system mógł je wykonać, wówczas powyższa metoda zawiedzie. W praktyce potrzebujesz (przynajmniej) tysięcy takich plików, ale może się zdarzyć.Stosowane metody
find
nie podlegają tym ograniczeniom, ponieważ:Sposób Zanny buduje i uruchamia
grep
polecenie z potencjalnie wieloma argumentami ścieżki. Ale jeśli znaleziono więcej plików, niż można je wyświetlić w jednej ścieżce, akcja+
-terminated-exec
uruchamia polecenie z niektórymi ścieżkami, a następnie uruchamia je ponownie z kilkoma ścieżkami i tak dalej. W przypadkugrep
wprowadzania ciągu w wielu plikach powoduje to prawidłowe zachowanie.Podobnie jak opisana tutaj metoda globstar, drukuje ona wszystkie pasujące linie, z dołączonymi do nich ścieżkami.
Droga sudodusa przebiega
grep
osobno dla każdegofile.txt
znalezionego. Jeśli jest wiele plików, może być wolniejsze niż niektóre inne metody, ale działa.Ta metoda wyszukuje pliki i drukuje ich ścieżki, a następnie pasujące linie, jeśli takie istnieją. Jest to inny format wyjściowy niż format utworzony przez moją metodę Zanna i Muru .
Uzyskiwanie koloru
find
Jedną z bezpośrednich korzyści płynących z używania globstar jest to, że domyślnie na Ubuntu
grep
produkuje kolorowe wydruki. Ale można łatwo dostać się z tymfind
też .Konta użytkowników w Ubuntu są tworzone za pomocą aliasu, który sprawia, że
grep
naprawdę działagrep --color=auto
(uruchom,alias grep
aby zobaczyć). To dobrze, że aliasy są dość dużo tylko rozszerzać, gdy wydasz je interaktywnie , ale oznacza to, że jeśli chceszfind
, aby wywołaćgrep
z--color
flagą, musisz napisać to wyraźnie. Na przykład:źródło
bash
powłoki, aby to zadziałało. Ty nie mów tego w sposób dorozumiany „opcją powłoki globstar bash”, ale może być łatwo pominięte przez ludzi zbyt szybko czyta.**
, twoja podstawowa krytyka jest poprawna: prezentacja**
w tej odpowiedzi jest specyficzna dla bash, z shopt tylko bash, a termin „globstar” to (myślę) bash i tylko tcsh. Zastanawiałem się nad tym pierwotnie z powodu tych złożoności, ale masz rację, że jest to trochę mylące. Zamiast omawiać go szczegółowo w tej odpowiedzi, podłączyłem do innego (dość dokładnego) postu, który wykonuje ciężkie podnoszenie.-e
że nie należy go stosować do ścieżek, ale można to łatwo naprawić. W przypadku pierwszego polecenia po prostu pomiń-e
. Po drugie użyjfind . -name file.txt -printf $'\e[32m%p:\e[0m\n' -exec grep -i "pattern" {} \;
lubfind . -name file.txt -exec printf '\e[32m%s:\e[0m\n' {} \; -exec grep -i "pattern" {} \;
. Użytkownicy czasem wolą twoją drogę (z-e
ustalonym użyciem) od innych, którzy drukują jedną ścieżkę na pasującą linię ; twoja drukuje jedną ścieżkę na znaleziony plik, a następniegrep
wyniki.grep
samo nie zrobi tego, co robisz. Niektóre inne krytyki również były błędne.grep -H
prowadzony przez-exec
woli nie kolorowania bez--color
(lubGREP_COLOR
). IEEE 1003.1-2008 nie gwarantuje{}
rozszerzenia##### {}:
, ale Ubuntu ma funkcję GNU find, która działa . Jeśli wszystko jest w porządku, zredaguję Twój post, aby naprawić-e
błąd (i wyjaśnię jego przypadek użycia), i zobaczysz, czy chcesz cofnąć usunięcie. (Mam przedstawiciela do przeglądania / edytowania usuniętych postów.)Nie potrzebujesz
find
tego;grep
radzi sobie z tym doskonale doskonale:Od
man grep
:źródło
find?
Sposób podany w odpowiedzi Muru jest , biegania
grep
z--include
flagą, aby określić nazwę pliku, jest często najlepszym wyborem. Można to jednak zrobić również za pomocąfind
.Podejście w tej odpowiedzi wykorzystuje się
find
do uruchomieniagrep
osobno dla każdego znalezionego pliku i wypisuje ścieżkę do każdego pliku dokładnie raz , powyżej pasujących wierszy znalezionych w każdym pliku. (Metody, które drukują ścieżkę przed każdą pasującą linią, są omówione w innych odpowiedziach).Możesz zmienić katalog na górę drzewa katalogów, w którym masz te pliki. Następnie uruchomić:
Spowoduje to wydrukowanie ścieżki (względem bieżącego katalogu
.
i samego pliku) każdego nazwanego plikufile.txt
, a następnie wszystkich pasujących wierszy w pliku. Działa{}
to, ponieważ jest symbolem zastępczym dla znalezionego pliku. Ścieżka każdego pliku jest oddzielana od jego zawartości, ponieważ jest poprzedzona znakiem#####
i jest drukowana tylko raz, przed pasującymi wierszami z tego pliku. (Wywołane pliki,file.txt
które nie zawierają żadnych dopasowań, nadal mają wydrukowane ścieżki). Może się okazać, że dane wyjściowe są mniej zagracone niż w przypadku metod, które drukują ścieżkę na początku każdej pasującej linii.Używanie w
find
ten sposób prawie zawsze będzie szybsze niż uruchamianiegrep
na każdym pliku (grep -arin "pattern" *
), ponieważfind
wyszukuje pliki o poprawnej nazwie i pomija wszystkie inne pliki.Ubuntu korzysta z wyszukiwania GNU , które zawsze rozwija się,
{}
nawet jeśli pojawia się w większym ciągu , np##### {}:
. Jeśli potrzebujesz komendy do pracyfind
w systemach, które mogą tego nie obsługiwać lub wolisz korzystać z-exec
akcji tylko wtedy, gdy jest to absolutnie konieczne, możesz użyć:Aby ułatwić odczytanie danych wyjściowych , możesz użyć sekwencji ucieczki ANSI, aby uzyskać kolorowe nazwy plików. To sprawia, że nagłówek ścieżki do każdego pliku wyróżnia się lepiej niż pasujące linie, które są drukowane pod nim:
To powoduje, że twoja powłoka przekształca kod zmiany znaczenia na zielony w rzeczywistą sekwencję zmiany znaczenia, która wytwarza kolor zielony w terminalu, i robi to samo z kodem zmiany znaczenia dla normalnego koloru. Te znaki ucieczki są przekazywane do
find
, który używa ich podczas drukowania nazwy pliku. ($'
'
Cytat jest konieczne tutaj, ponieważfind
„s-printf
działania nie rozpoznaje\e
interpretowania kody ucieczki ANSI).Jeśli wolisz, możesz zamiast korzystać
-exec
z systemuprintf
dowodzenia (który obsługuje\e
). Kolejnym sposobem na zrobienie tego samego jest:źródło
find abc/def/efg -name "file.txt" -type f -exec echo -e "##### {}:" \; -exec grep -i "pattern" {} \;
cd abc/def/efg
„zmień katalog” :-)-e
opcjęecho
? Spowoduje to, że zmieni on nazwy plików zawierające ukośniki odwrotne. (2) Przy użyciu{}
jako część argument nie gwarantuje pracę. Lepiej byłoby powiedzieć-exec echo "#####" {} \;
lub-exec printf "##### %s:\n" {} \;
. (3) Dlaczego nie po prostu użyć-print
lub-printf
? (4) Zastanów się takżegrep -H
.find . -name "file.txt" -type f -exec echo -e "\0033[32m{}:\0033[0m" \; -exec grep -i "pattern" {} \;
2) Być może masz rację, ale jak na razie to działa. 3) -print i -printf są również alternatywami. 4) To już jest w głównej odpowiedzi. - W każdym razie jesteś mile widziany z własną odpowiedzią :-)-exec
połączeń. Wystarczy użyćgrep -H
, aby wydrukować nazwę pliku (w kolorze), a także dopasowany tekst.Aby wskazać, że jeśli warunki pytania mogą być wzięte z literatury, możesz użyć bezpośredniego grep:
lub
źródło