Bagaimana cara melewati daftar file untuk di-grep

98

Saya menggunakan finddan mendapatkan daftar file yang ingin saya greplalui. Bagaimana cara saya mem-pipe list itu grep?

Arcabard
sumber

Jawaban:

116

Nah, kasus umum yang bekerja dengan perintah apa pun yang menulis ke stdout adalah menggunakan xargs, yang akan memungkinkan Anda melampirkan sejumlah argumen baris perintah ke akhir perintah:

$ find … | xargs grep 'search'

Atau untuk menanamkan perintah di grepbaris Anda dengan backticks atau $(), yang akan menjalankan perintah dan mengganti hasilnya:

$ grep 'search' $(find …)

Perhatikan bahwa perintah ini tidak berfungsi jika nama file berisi spasi, atau "karakter aneh" tertentu lainnya ( \'"untuk xargs, \[*?untuk $(find …)).


Namun, dalam kasus khusus findkemampuan untuk mengeksekusi program pada argumen yang diberikan adalah bawaan:

$ find … -exec grep 'search' {} \;

Segala sesuatu di antara -execdan ;merupakan perintah untuk dijalankan; {}diganti dengan nama file yang ditemukan oleh find. Itu akan mengeksekusi terpisah grepuntuk setiap file; karena grepdapat mengambil banyak nama file dan mencari semuanya, Anda dapat mengubah ;to +to tell find untuk meneruskan semua nama file yang cocok grepsekaligus:

$ find … -exec grep 'search' {} \+
Michael Mrozek
sumber
1
Harus dicatat bahwa dua bentuk pertama tidak berfungsi dengan nama file yang mengandung spasi.
enzotib
1
Saya lebih suka find ... -type f -print0 | xargs -r0 grep 'search' /dev/null. QED. Meskipun -exec +sangat efisien, itu tidak ada di semua versi find.
Arcege
Sayangnya saya tidak dapat memeriksa Anda benar 3 kali.
Arcabard
3
Saya sarankan menggunakan -exec, daripada xargs. Jika Anda menggunakan -execdi find, itu akan membuat hanya satu shell ke grep untuk konten. Jika Anda menggunakan xargs, itu akan membuat dua cangkang: satu untuk finddan yang lain untuk xargs.
2
dengan eksperimen saya menemukan bahwa $ find … -exec grep 'search' {} \+formulir jauh lebih cepat.
gogoud
9

Beberapa versi grep(misalnya pada Linux yang tidak tertanam atau BSD atau Mac OS X) memiliki -ropsi untuk melakukan pencarian rekursif. Pada OpenBSD, gunakan -R(dan tidak ada --excludeseperti pada contoh di bawah). Ini mencakup kombinasi sederhana finddengan grep.

Jika implementasi Anda tidak memiliki -Rbendera, atau jika Anda ingin kriteria pencocokan file yang lebih bagus, Anda dapat menggunakan -executama finduntuk membuatnya mengeksekusi grep. Beberapa findimplementasi lama tidak mendukung -exec... +; pada sistem ini, gunakan ;bukan +(ini akan memanggil grepsekali per file, jadi akan lebih lambat, tetapi jika tidak hasilnya akan sama). Perhatikan /dev/nulltrik yang menyebabkan grepmenampilkan nama file bahkan jika kebetulan dipanggil pada satu file (grep GNU dan grep FreeBSD / NetBSD / OSX memiliki -Hopsi untuk mencapai efek yang sama).

find . -type f -name '*.o' -prune -o -exec grep 'needle' /dev/null {} +
grep -r --exclude='*.o' 'needle' .
Gilles
sumber
2
GNU grepmemiliki -Hopsi untuk selalu mencetak nama file.
enzotib