Jak mogę grep wyniki FIND przy użyciu -EXEC i nadal wyprowadzać do pliku?

64

Lepiej wyjaśnić na przykładach.

Mogę:

find . -name "*.py" -type f > output.txt

Ale jak mogę zapisać dane wyjściowe w tym samym pliku dla:

find . -name "*.py" -type f -exec grep "something" {} \

Nie mogę tak po prostu zrobić

find . -name "*.py" -type f -exec grep "something" {} \ > output.txt
bakytn
źródło

Odpowiedzi:

105

Jeśli dobrze cię rozumiem, to właśnie chcesz zrobić:

find . -name '*.py' -print0 | xargs -0 grep 'something' > output.txt

Findwszystkie pliki z rozszerzeniem py, greptylko wiersze zawierające somethingi zapisujące wiersze output.txt. Jeśli plik zawiera coś, zostanie zastąpiony.

Edytuj: Używając -exec:

find . -name '*.py' -exec grep 'something' {} \; > output.txt

Zamieszczam tutaj komentarz Chrisa Downsa. Powyższe polecenie spowoduje grepwykonanie tyle razy, ile razy wystąpi find. Jednak jeśli zamienisz na ;a +, grepzostanie wywołany z wyjściem z findkonkatenacji (do pewnego limitu). Zobacz pytanie Używanie średnika (;) vs plus (+) z exec w celu znalezienia dodatkowych informacji na ten temat.

Jasio
źródło
16
Użyj +zamiast \;, znacznie skróci czas wykonywania (ponieważ będzie zawierał argumenty przed wykonaniem do ARG_MAX).
Chris Down,
Teraz rozumiem moc xargs! Dzięki!
domih
4
Użyj, grep -Hjeśli chcesz dołączyć nazwę pliku do wyniku.
Steinar,
18

Jeśli chcesz zapisać wszystkie pasujące linie we wszystkich plikach output.txt, twoje ostatnie polecenie działa, z wyjątkiem tego, że brakuje wymaganego ;na końcu polecenia.

find . -name "*.py" -type f -exec grep "something" {} \; > output.txt

Jeśli chcesz, aby każde uruchomienie grepgenerowało dane wyjściowe do innego pliku, uruchom powłokę, aby obliczyć nazwę pliku wyjściowego i wykonać przekierowanie.

find . -name "*.py" -type f -exec sh -c 'grep "something" <"$0" >"$0.txt"' {} \;
Gilles
źródło
ostatni naprawdę fajny: D
bakytn
Aby rozwinąć odpowiedź @gilles i uczynić ją nieco bardziej pouczającą, szczególnie jeśli lista plików, z którymi masz do czynienia, jest duża, możesz zgłosić nazwę pliku (ścieżkę względną) każdego pliku wraz z wynikami grep'ed, używając tego : find . -name "*.py" -type f -exec grep "something" {} \; -print > output.txt A jeśli chcesz zobaczyć numery linii grep'ed, możesz oczywiście użyćgrep -n "something"
JJMpls
9

Dla przypomnienia, grepma --includei --excludeargumenty, które można wykorzystać do filtrowania plików przeszukuje:

grep -r --include="*.py" "something" > output.txt
hunse
źródło
2
Przynajmniej GNU to greprobi.
phk
2

Użyj tee:

find . -name '*.py' | tee output.txt | xargs grep 'something'

Zastrzeżenie, to jeśli masz żadnych plików ze znakami specjalnymi (łącznie ze spacjami), które xargsi grepnie będą dobrze pracować ( a file.txtbędą interpretowane jako dwa pliki, aa file.txt). Alternatywą jest użycie albo -xOr -print0, ale żadnej z tych będzie zanieczyścić output.txt. -xUżyje \do ucieczki niektórych znaków specjalnych i to będzie output.txt. -print0Użyje zerowy bajt jako separatora pól (co wymaga również xargs -0) i output.txtbędzie wyglądać jak jeden długi ciągłej linii tekstu.

To, jak sobie z tym poradzisz (lub nie), zależy od ciebie.

bahamat
źródło