Come reindirizzare l'elenco dei file restituiti dal comando find a cat per visualizzare tutti i file


204

Sto facendo un finde quindi ottenere un elenco di file. Come posso collegarlo a un'altra utility come cat(in modo che cat mostri il contenuto di tutti quei file) e fondamentalmente abbia bisogno di grepqualcosa da questi file.

Risposte:


340
  1. Piping su un altro processo (anche se questo NON riuscirà a realizzare ciò che hai detto che stai cercando di fare):

    command1 | command2
    

    Questo invierà l'output di command1 come input di command2

  2. -execsu un find(questo farà quello che vuoi fare - ma è specifico per find)

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

    (Tutto tra finde -execsono i predicati find che stavi già utilizzando. {}Sostituirà il particolare file che hai trovato nel comando ( cat {}in questo caso); \;è quello di terminare il -execcomando.)

  3. invia l'output di un processo come argomento della riga di comando a un altro processo

    command2 `command1`
    

    per esempio:

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

    (Nota che questi sono BACK-QUOTES non virgolette regolari (sotto la tilde ~ sulla mia tastiera).) Questo invierà l'output di command1in command2come argomenti della riga di comando. Tuttavia, i nomi dei file contenenti spazi (newline, ecc.) Verranno suddivisi in argomenti separati.


2
cat ha find -name '*.foo' -printfunzionato benissimo per me ... Grazie
Devang Kamdar,

I backquotes funzionano benissimo ed è più generalizzato, puoi usarlo anche per catalogare un elenco di file da un file.
Hazok,

11
Si noti che le versioni moderne di findconsentono di scrivere:, find . -name '*.foo' -exec cat {} +dove +indica che finddovrebbero raggruppare tutti i nomi di file più convenienti in un'unica chiamata di comando. Questo è abbastanza utile (si occupa di spazi ecc. Nei nomi dei file senza ricorrere a -print0e xargs -0).
Jonathan Leffler,

18
Non menzionato:find . -name '*.foo' | xargs cat
stufato al quadrato

3
Giusto per aggiungere alla risposta @stewSquared s: Per trovare tutte le righe di file che contengono una certa stringa, farefind . -name '*.foo' | xargs cat | grep string
Bim

84

Versione moderna

POSIX 2008 ha aggiunto il +marcatore a findcui ora raggruppa automaticamente tutti i file ragionevoli in un'unica esecuzione di comando, proprio come xargsfa, ma con una serie di vantaggi:

  1. Non devi preoccuparti di caratteri strani nei nomi dei file.
  2. Non devi preoccuparti che il comando venga invocato con zero nomi di file.

Il problema del nome file è un problema con xargssenza l' -0opzione e il problema "esegui anche con zero nomi file" è un problema con o senza l' -0opzione - ma GNU xargsha il -ro--no-run-if-empty opzione per impedire che ciò accada. Inoltre, questa notazione riduce il numero di processi, non che tu possa misurare la differenza nelle prestazioni. Quindi, potresti scrivere sensatamente:

find . -exec grep something {} +

Versione classica

find . -print | xargs grep something

Se sei su Linux o hai GNU finde xargscomandi, usa -print0con finde -0conxargs per gestire i nomi dei file contenenti spazi e altri caratteri dispari.

find . -print0 | xargs -0 grep something

Ottimizzare i risultati da grep

Se non desideri i nomi dei file (solo il testo), aggiungi un'opzione appropriata a grep(di solito -hper sopprimere le "intestazioni"). Per garantire assolutamente che il nome del file sia stampato da grep(anche se viene trovato un solo file o all'ultima chiamata di grepviene assegnato solo 1 nome file), quindi aggiungere/dev/null alla xargsriga di comando, in modo che ci siano sempre almeno due nomi di file.


Per quelli confusi come me, notare che in questo modo verrà innanzitutto fornito tutto l'output di find, quindi verrà fornito l'output di xargs grep something.
Eric Hu,

3
@EricHu: Vedo che sei confuso, ma non fa quello che dici, almeno non su alcun sistema basato su Unix che conosco. L'output di findviene reindirizzato all'input standard di xargs. Il xargsprogramma legge l'input standard, suddividendo l'input su uno spazio bianco (spazi vuoti, newline, tab, ecc.) E aggiunge un numero di parole al comando grep somethinged esegue la riga di comando. xargsquindi continua a leggere l'input e ad eseguire i comandi finché non si esaurisce l'input. xargsesegue il grepcomando tutte le volte che è necessario per l'input fornito (da findquesto esempio).
Jonathan Leffler,

Ah, mio ​​errore, sto usando grep per cercare all'interno di ogni file corrispondente. Stavo cercando di filtrare semplicemente l'output di find con grep
Eric Hu,

1
Gli errori vanno all'errore standard (descrittore di file 2) su tutti i comandi ben educati. Reindirizzare stderr per /dev/nullperdere i messaggi di errore.
Jonathan Leffler,

1
Questo ha anche il vantaggio di funzionare meglio con gli spazi nel percorso del file. Anche 'sed'ing "" -> "\" lo rompe con il `ma con xargs funziona perfettamente
JZL003

36

Esistono alcuni modi per passare l'elenco dei file restituiti dal findcomando al catcomando, sebbene tecnicamente non tutti utilizzino il piping e nessuno effettivamente esegua il pipe direttamente cat.

  1. Il più semplice è usare i backtick ( `):

    cat `find [whatever]`
    

    Questo prende l'output di finde lo posiziona efficacemente sulla riga di comando di cat. Questo non funziona bene se findha un output eccessivo (più di quello che può stare su una riga di comando) o se l'output ha caratteri speciali (come gli spazi).

  2. In alcune shell, incluso bash, si possono usare al $()posto dei backtick:

    cat $(find [whatever])
    

    Questo è meno portatile, ma è annidabile. A parte questo, ha praticamente le stesse avvertenze dei backtick.

  3. Poiché l'esecuzione di altri comandi su ciò che è stato trovato è un uso comune per find, find ha -execun'azione che esegue un comando per ogni file che trova:

    find [whatever] -exec cat {} \;
    

    Il {}è un segnaposto per il nome del file, e le \;segna la fine del comando (è possibile avere altre azioni dopo -exec.)

    Questo verrà eseguito catuna volta per ogni singolo file anziché eseguire una singola istanza di catpassare più nomi di file che può essere inefficiente e potrebbe non avere il comportamento desiderato per alcuni comandi (anche se va bene cat). Anche la sintassi è una cosa scomoda da digitare: è necessario sfuggire al punto e virgola perché il punto e virgola è speciale per la shell!

  4. Alcune versioni di find(in particolare la versione GNU) consentono di sostituire ;con +un uso -exec'accodamento s per eseguire un minor numero di casi di cat:

    find [whatever] -exec cat {} +
    

    Questo passerà più nomi di file a ogni invocazione di cat, che può essere più efficiente.

    Si noti che ciò non garantisce l'utilizzo di una singola chiamata. Se la riga di comando fosse troppo lunga, gli argomenti vengono suddivisi su più invocazioni di cat. Per catquesto probabilmente non è un grosso problema, ma per alcuni altri comandi questo può cambiare il comportamento in modi indesiderati. Sui sistemi Linux, il limite di lunghezza della riga di comando è piuttosto elevato, quindi la suddivisione in più invocazioni è piuttosto rara rispetto ad altri sistemi operativi.

  5. L'approccio classico / portatile consiste nell'utilizzare xargs:

    find [whatever] | xargs cat
    

    xargsesegue il comando specificato ( cat, in questo caso) e aggiunge argomenti in base a ciò che legge da stdin. Proprio come -execcon +, questo interromperà la riga di comando, se necessario. Cioè, se findproduce troppo output, verrà eseguito catpiù volte. Come menzionato nella sezione -execprecedente, ci sono alcuni comandi in cui questa suddivisione può comportare comportamenti diversi. Si noti che l'utilizzo in xargsquesto modo ha problemi con gli spazi nei nomi dei file, in quanto xargsutilizza solo gli spazi bianchi come delimitatore.

  6. Il metodo più robusto, portatile ed efficiente utilizza anche xargs:

    find [whatever] -print0 | xargs -0 cat
    

    Il -print0flag dice finddi usare \0delimitatori (carattere null) tra i nomi di file e il -0flag dice xargsdi aspettarsi questi \0delimitatori. Questo ha un comportamento praticamente identico all'approccio -exec... +, sebbene sia più portatile (ma sfortunatamente più prolisso).


Il metodo backtick è eccezionale, perché funziona anche per altri comandi come ls.
Martin Braun,

@Martin Braun usando $()Funziona anche con comandi diversi da find .
Laurence Gonsalves

Grazie, buono a sapersi, ho smesso di leggere dopo (1), perché soddisfa le mie esigenze, dal momento che non ho a che fare con personaggi speciali come spazi e simili.
Martin Braun

9

Per raggiungere questo obiettivo (usando bash) farei quanto segue:

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

Questo è noto come "sostituzione di comando" e, di default, elimina l'alimentazione di riga, il che è davvero conveniente!

maggiori informazioni qui


6

Mi sembra un lavoro per uno script di shell:

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

o qualcosa di simile


2
Questa è una risposta valida, sebbene non necessariamente ottimale, alla domanda.
Jonathan Leffler,

1
... sì, ma è fantastico se vuoi anche un file di grandi dimensioni con nomi di file elencati.
ʍǝɥʇɐɯ

1
Mi piace di più. Un blocco ad anello come questo lascia spazio per fare altre cose.
Kakyo,

4

Ecco il mio modo di trovare nomi di file che contengono alcuni contenuti che mi interessano, solo una singola riga bash che gestisce bene anche gli spazi nei nomi dei file:

find . -name \*.xml | while read i; do grep '<?xml' "$i" >/dev/null; [ $? == 0 ] && echo $i; done

3

Uso qualcosa del genere:

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

" -print0" argomento per "find" e " -0" argomento per "xargs" sono necessari per gestire correttamente gli spazi nei percorsi / nomi dei file.



2

Ecco il mio scatto per uso generale:

grep YOURSTRING `find .`

Stampa il nome del file


2

In bash, sarebbe appropriato:

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

Questo troverà tutti i file nella /dirdirectory e inoltrerà in modo sicuro i nomi dei file xargs, che guideranno in sicurezzagrep .

Saltare xargsnon è una buona idea se hai molte migliaia di file /dir; catsi interromperà a causa dell'eccessiva lunghezza dell'elenco degli argomenti.xargsrisolverà tutto per te.

L' -print0argomento da findassociare -0all'argomento xargsper gestire correttamente i nomi di file con spazi. L' -iargomento per xargsconsentire di inserire il nome file dove richiesto nella catriga di comando. Le parentesi vengono sostituite dal nome file reindirizzato nel catcomando da find.


0

Questo funziona per me

find _CACHE_* | while read line; do
    cat "$line" | grep "something"
done

0

Usa ggrep .

ggrep -H -R -I "mysearchstring" *

per cercare un file in unix contenente testo situato nella directory corrente o in una sottodirectory


0

Questo stamperà ricorsivamente il nome e il contenuto dei soli file.

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

Modifica (versione migliorata): questo stamperà ricorsivamente il nome e il contenuto dei file di testo (ascii).

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

Un altro tentativo

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

-1

Stai cercando di trovare testo nei file? Puoi semplicemente usare grep per quello ...

grep searchterm *

-1

Per elencare e vedere i contenuti di tutti i file abc.def su un server nelle directory / ghi e / jkl

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

Per elencare i file abc.def che hanno voci commentate e visualizzate, vedere quelle voci nelle directory / ghi e / jkl

find /ghi /jkl -type f -name abc.def 2> /dev/null -exec grep -H ^# {} \;
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.