Jak używać grep na wszystkich plikach nierekurencyjnie w katalogu?

34

Chcę wyszukać ciąg tekstu we wszystkich plikach w katalogu (a nie w jego podkatalogach; wiem, że -ropcja to robi, ale nie tego chcę).

  1. Bieganie

    grep "string" /path/to/dir
    

    powinienem to zrobić, przeczytałem, ale daje mi to błąd:

    grep: dir: to katalog

  2. Następnie próbowałem uruchomić grepna wielu plikach.

    grep "string" .bashrc .bash_aliases działa świetnie.

    grep "string" .bash* działa również zgodnie z przeznaczeniem.

    grep "string" * daje mi błędy:

    grep: data: Is a directory
    grep: Desktop: Is a directory
    grep: Documents: Is a directory
    grep: Downloads: Is a directory
    ...
    

Drukowane są tylko błędy, nie otrzymuję pasujących linii. Próbowałem użyć tej -sopcji, ale bezskutecznie.

Więc moje pytania:

  1. Dlaczego nie mogę korzystać grepz katalogu, jak w (1), kiedy powinienem? Widziałem to w wielu przykładach w Internecie.
    Edycja : Kiedy mówię „używając grep w katalogu”, mam na myśli „szukaj we wszystkich plikach w tym katalogu oprócz jego podkatalogów”. Uważam, że to właśnie robi grep, gdy przekazujesz do niego katalog zamiast pliku. Czy jestem w błędzie?

  2. Proszę o wyjaśnienie działania grep, które wyjaśniłoby zachowanie poleceń w (2).
    Edycja : Pozwól mi być bardziej szczegółowy. Dlaczego za pomocą symboli wieloznacznych określa się wiele plików, w których ma być wyszukiwana praca, .bash*a *nawet nie, a nawet ./*?

  3. Jak mogę wyszukiwać wszystkie pliki w katalogu (a nie w jego podkatalogach) za pomocą grep?

John Red
źródło
*Opierasz się również na znakach wieloznacznych rozszerzających powłoki, takich jak globbing. Globowanie nie obejmuje nazw plików rozpoczynających się od kropki, takiej .bashrcjak standardowa. Możesz ustawić opcje powłoki, aby zawierały te pliki, ale możesz wpaść w bałagan, jeśli nie wiesz, co robisz. Dobry przewodnik po zrozumieniu globowania można znaleźć tutaj mywiki.wooledge.org/glob
Arronical
Nie wiem dlaczego, ale zawsze robiłem globowanie ukrytych plików i zawsze działało. Nie zmieniłem żadnego ustawienia ani czegoś takiego. Jak wskazałem w (2), działa grep "string" .bash*również z .
John Red,
Przepraszam, mój ostatni przykład był niepoprawny. Możesz także wyszukiwać ukryte pliki i pomijać „katalog”, ponieważ Linux technicznie postrzega katalogi jako inny typ pliku. Polecenie brzmiałoby wtedy: grep "string" * .* 2>/dev/nulllubgrep -s "string" * .*
Terrance
Również ten stackoverflow.com/q/9217185/3701431
Sergiy Kolodyazhnyy

Odpowiedzi:

40

W Bash glob nie będzie rozwijał się do ukrytych plików, więc jeśli chcesz przeszukać wszystkie pliki w katalogu, musisz określić pliki ukryte .*i nie ukryte *.

Aby uniknąć błędów „Czy katalog”, możesz użyć -d skip, ale w moim systemie również pojawia się błąd grep: .gvfs: Permission denied , więc sugeruję użycie -s, które ukrywa wszystkie komunikaty o błędach.

Polecenie, którego szukasz, to:

grep -s "string" * .*

Jeśli szukasz plików w innym katalogu:

grep -s "string" /path/to/dir/{*,.*}

Inną opcją jest użycie dotglobopcji powłoki, która sprawi, że glob będzie zawierać ukryte pliki.

shopt -s dotglob
grep -s "string" *

W przypadku plików w innym katalogu:

grep -s "string" /path/to/dir/*

† Ktoś wspomniał, że nie powinienem dostać tego błędu. Mogą mieć rację - przeczytałem trochę, ale sam nie mogłem zrobić głów ani ogonów.

wjandrea
źródło
Czy jest jakiś powód dla odstępu między *i .*?
Hashim
2
@Hashim Porównaj dane wyjściowe echo * .*i echo *.*uruchom w swoim katalogu domowym, a różnica powinna być oczywista. W przeciwnym razie LMK i wyjaśnię to.
wjandrea,
Interesujące, więc echo *pokazuje nie ukryte pliki i foldery, echo *.*pokazuje nie ukryte pliki, echo .*pokazuje wszystkie pliki i echo * .*pokazuje wszystkie pliki i katalogi. Ale dlaczego powód odstępu między nimi w tym drugim przypadku? Czuję się niechlujny. Czy nie ma sposobu na połączenie tych dwóch, aby uzyskać takie same wyniki? Czy w przeciwnym razie istnieje wyjaśnienie składniowe, dlaczego należy je tutaj rozdzielić, czy też jest * .*to wyjątkowy przypadek?
Hashim
1
@Hashim Nie jestem pewien, jak doszedłeś do tych wniosków, więc pozwól mi wyjaśnić. Po pierwsze, katalogi są plikami w tym kontekście. W globach *reprezentuje wszystkie nie ukryte pliki (tzn. Nazwy plików, które nie zaczynają się od kropki); .*reprezentuje wszystkie ukryte pliki (czyli nazwy plików, które nie zaczynają się od kropki); i *.*reprezentuje wszystkie nie ukryte pliki zawierające kropkę. W echo * .*te dwa globs muszą być oddzielone, ponieważ są one różne globs: jeden dla non-ukryte, jeden dla ukryty. Chociaż, jak napisałem w mojej odpowiedzi, możesz włączyć *dołączanie ukrytych plików, włączając dotglobopcję powłoki.
wjandrea
1
Używanie *.*jest powszechne w systemie Windows (DOS) jako sposób na wyświetlenie listy wszystkich plików, ale w * nix będzie zawierać tylko pliki z kropką, więc nie ma to sensu w * nix. Zamiast tego używasz, *aby wyświetlić listę wszystkich plików oprócz plików ukrytych oraz .*listę plików ukrytych.
thomasrutter
10

Potrzebujesz -d skipdodanej opcji.

  1. Grep przeszukuje pliki. Możesz wyszukiwać rekurencyjnie, jak powiedziałeś, jeśli chcesz przeszukiwać pliki w katalogu.

  2. Domyślnie grep odczytuje wszystkie pliki i wykrywa katalogi. Ponieważ domyślnie nie zdefiniowano, co zrobić z katalogami z tą -dopcją, daje to wynik błędu.

  3. Wyszukiwanie tylko w katalogu nadrzędnym byłoby `grep -d pomiń" string "./*

anonimowy 2
źródło
Aby uzyskać więcej informacji na temat grep, zobacz man grep.
anonimowy2
(a) Proszę zobaczyć edycję. (b) Korzystanie -d skipnie działa; jest w zasadzie taki sam jak -s; zobacz także edycję. (c) Nie, grep -d skip "string" ./*też nie działa.
John Red,
7

Dawni zegary prawdopodobnie zrobiliby to:

find . -type f -print0 | xargs -0 grep "string"
dathompson
źródło
3
Dlaczego nie find . -type f -exec grep string {} +?
wchargin
5
Ty też chcesz -maxdepth 1.
wchargin
@wchargin: jeśli chcesz nazwę pliku na wyjściu, gdy jest tylko jeden plik, myślę, że chceszfind . -type f -maxdepth 1 -exec grep string /dev/null {} +
Gregory Nisbet
1
@GregoryNisbet: Po prostu przejdź -Hdo grep.
wchargin
2

Przeprojektowanie - chcesz grepować pliki w jednym poziomie podkatalogu, ale nie powtarzać się we wszystkich podkatalogach?

grep forthis  *  */*

Lub jeśli nie chcesz plików w bieżącym katalogu

grep forthis  */*

Zauważ, że nie znajdzie katalogów zaczynających się od kropki.

grep forthis  .*/*    */*   

powinien wykonać tę pracę.

Jest też -maxdepthi -mindepthograniczenie Parametry dostępne dla findkomendy zbyt.

Criggie
źródło
Czy nie grep forthis */*wyszukiwałby plików zarówno w bieżącym katalogu, jak i w jednym katalogu?
Hashim
@Hashim nie, głównie - cos */*pasuje tylko do jednego ukośnika. Jeśli miałeś plik o nazwie a/bw bieżącym katalogu, to `* / * pasowałby do niego.
Criggie,
0

Oto przykład pomijania katalogów bez pomijania wszystkich błędów:

grep --directories='skip' 'searchString' *
Mojtaba Rezaeian
źródło