Cara mem-pipe daftar file yang dikembalikan dengan perintah find to cat untuk melihat semua file

204

Saya melakukan finddan kemudian mendapatkan daftar file. Bagaimana cara saya catmengirim pipa ke utilitas lain seperti (sehingga kucing menampilkan konten semua file itu) dan pada dasarnya perlu grepsesuatu dari file-file ini.

Devang Kamdar
sumber

Jawaban:

340
  1. Perpipaan ke proses lain (Meskipun ini TIDAK AKAN mencapai apa yang Anda katakan Anda coba lakukan):

    command1 | command2
    

    Ini akan mengirim output dari command1 sebagai input dari command2

  2. -execpada find(ini akan melakukan apa yang ingin Anda lakukan - tetapi khusus untuk find)

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

    (Segala sesuatu di antara finddan -execadalah predikat find yang sudah Anda gunakan. {}Akan mengganti file tertentu yang Anda temukan dalam perintah ( cat {}dalam hal ini); \;adalah untuk mengakhiri -execperintah.)

  3. mengirim output dari satu proses sebagai argumen baris perintah ke proses lain

    command2 `command1`
    

    sebagai contoh:

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

    (Perhatikan ini adalah BACK-QUOTES bukan kutipan reguler (di bawah tilde ~ di keyboard saya).) Ini akan mengirimkan output command1menjadi command2sebagai argumen baris perintah. Perhatikan bahwa nama file yang mengandung spasi (baris baru, dll) akan dipecah menjadi argumen yang terpisah.

kenj0418
sumber
2
kucing find -name '*.foo' -printbekerja sangat baik untuk saya ... Terima kasih
Devang Kamdar
Backquotes berfungsi dengan baik dan lebih digeneralisasi, Anda dapat menggunakan ini untuk menyimpan daftar file dari file juga.
Hazok
11
Perhatikan bahwa versi modern findmemungkinkan Anda untuk menulis:, di find . -name '*.foo' -exec cat {} +mana +menunjukkan bahwa findharus mengelompokkan sebanyak mungkin nama file ke dalam satu permintaan perintah tunggal. Ini cukup berguna (ini berkaitan dengan spasi dll dalam nama file tanpa menggunakan -print0dan xargs -0).
Jonathan Leffler
18
Tidak disebutkan:find . -name '*.foo' | xargs cat
stewSquared
3
Hanya dengan menambahkan jawaban @stewSquared: Untuk menemukan semua baris dalam file yang berisi string tertentu, lakukanfind . -name '*.foo' | xargs cat | grep string
Bim
84

Versi modern

POSIX 2008 menambahkan +penanda findyang berarti sekarang secara otomatis mengelompokkan file sebanyak yang masuk akal ke dalam satu eksekusi perintah, sangat mirip xargs, tetapi dengan sejumlah keuntungan:

  1. Anda tidak perlu khawatir tentang karakter aneh dalam nama file.
  2. Anda tidak perlu khawatir tentang perintah yang dijalankan dengan nol nama file.

Masalah nama file adalah masalah xargstanpa -0opsi, dan masalah 'run even with zero file names' adalah masalah dengan atau tanpa -0opsi - tetapi GNU xargsmemiliki -ratau --no-run-if-emptyopsi untuk mencegah hal itu terjadi. Juga, notasi ini mengurangi jumlah proses, bukan berarti Anda cenderung mengukur perbedaan kinerja. Karenanya, Anda dapat menulis dengan bijaksana:

find . -exec grep something {} +

Versi klasik

find . -print | xargs grep something

Jika Anda menggunakan Linux atau memiliki GNU finddan xargsperintah, gunakan -print0dengan finddan -0dengan xargsuntuk menangani nama file yang berisi spasi dan karakter ganjil lainnya.

find . -print0 | xargs -0 grep something

Tweak hasil dari grep

Jika Anda tidak ingin nama file (hanya teks) maka tambahkan opsi yang sesuai untuk grep(biasanya -huntuk menekan 'judul'). Untuk benar-benar menjamin nama file dicetak oleh grep(bahkan jika hanya satu file ditemukan, atau doa terakhir grephanya diberikan 1 nama file), kemudian tambahkan /dev/nullke xargsbaris perintah, sehingga akan selalu ada setidaknya dua nama file.

Jonathan Leffler
sumber
Bagi mereka yang bingung seperti saya, perhatikan bahwa cara ini pertama akan memberikan semua hasil pencarian, dan kemudian memberikan hasil xargs grep something.
Eric Hu
3
@ EricHu: Saya dapat melihat Anda bingung, tetapi tidak melakukan apa yang Anda katakan, setidaknya tidak pada sistem berbasis Unix yang saya tahu. Output dari finddisalurkan ke input standar xargs. The xargsprogram membaca masukan standar, membelah input di ruang putih (kosong, baris baru, tab, dll) dan menambahkan sejumlah kata-kata untuk perintah grep somethingdan mengeksekusi baris perintah. xargskemudian melanjutkan membaca input dan mengeksekusi perintah sampai kehabisan input. xargsmenjalankan grepperintah sesering yang diperlukan untuk input yang diberikan (dari finddalam contoh ini).
Jonathan Leffler
Ah kesalahan saya, ini menggunakan grep untuk mencari dalam setiap file yang cocok. Saya mencari untuk hanya memfilter output dari find dengan grep
Eric Hu
1
Kesalahan menuju ke kesalahan standar (deskriptor file 2) pada semua perintah yang berperilaku baik. Mengarahkan stderr untuk /dev/nullkehilangan pesan kesalahan.
Jonathan Leffler
1
Ini juga memiliki manfaat yang berfungsi lebih baik dengan spasi di jalur file. Bahkan 'sed'ing "" -> "\" memecahnya dengan `tetapi dengan xargs berfungsi dengan baik
JZL003
36

Ada beberapa cara untuk meneruskan daftar file yang dikembalikan oleh findperintah ke catperintah, meskipun secara teknis tidak semua menggunakan perpipaan, dan tidak ada yang benar-benar disalurkan langsung ke cat.

  1. Yang paling sederhana adalah menggunakan backticks ( `):

    cat `find [whatever]`
    

    Ini mengambil output finddan secara efektif menempatkannya di baris perintah cat. Ini tidak berfungsi dengan baik jika findmemiliki terlalu banyak output (lebih dari yang bisa muat pada baris perintah) atau jika output memiliki karakter khusus (seperti spasi).

  2. Dalam beberapa shell, termasuk bash, seseorang dapat menggunakan $()bukannya backticks:

    cat $(find [whatever])
    

    Ini kurang portabel, tetapi bisa ditumpuk. Selain itu, ia memiliki banyak peringatan yang sama dengan backticks.

  3. Karena menjalankan perintah lain pada apa yang ditemukan adalah penggunaan umum find, find memiliki -exectindakan yang mengeksekusi perintah untuk setiap file yang ditemukan:

    find [whatever] -exec cat {} \;
    

    The {}adalah sebuah tempat untuk nama file, dan \;menandai akhir perintah (Ini mungkin untuk memiliki tindakan lain setelah-exec .)

    Ini akan berjalan catsekali untuk setiap file tunggal daripada menjalankan satu contoh catmelewati itu beberapa nama file yang bisa tidak efisien dan mungkin tidak memiliki perilaku yang Anda inginkan untuk beberapa perintah (meskipun itu baik untuk cat). Sintaksnya juga canggung untuk mengetik - Anda harus keluar dari titik koma karena titik koma khusus untuk shell!

  4. Beberapa versi find(terutama versi GNU) memungkinkan Anda mengganti ;dengan +menggunakan -execmode tambahkan untuk menjalankan lebih sedikit contoh cat:

    find [whatever] -exec cat {} +
    

    Ini akan memberikan beberapa nama file ke setiap permintaan cat, yang bisa lebih efisien.

    Perhatikan bahwa ini tidak dijamin untuk menggunakan doa tunggal. Jika baris perintah terlalu panjang maka argumen tersebar di beberapa permintaan cat. Untuk catini mungkin bukan masalah besar, tetapi untuk beberapa perintah lain ini dapat mengubah perilaku dengan cara yang tidak diinginkan. Pada sistem Linux, batas panjang baris perintah cukup besar, sehingga pemisahan menjadi beberapa pemanggilan cukup jarang dibandingkan dengan beberapa OS lainnya.

  5. Pendekatan klasik / portabel adalah dengan menggunakan xargs:

    find [whatever] | xargs cat
    

    xargsmenjalankan perintah yang ditentukan ( cat, dalam kasus ini), dan menambahkan argumen berdasarkan apa yang dibaca dari stdin. Sama seperti -execdengan +, ini akan memecah baris perintah jika perlu. Artinya, jika findmenghasilkan terlalu banyak output, itu akan berjalan catbeberapa kali. Seperti disebutkan di bagian tentang -execsebelumnya, ada beberapa perintah di mana pemisahan ini dapat mengakibatkan perilaku yang berbeda. Perhatikan bahwa menggunakan xargsseperti ini memiliki masalah dengan spasi dalam nama file, karena xargshanya menggunakan spasi sebagai pembatas.

  6. Metode yang paling kuat, portabel, dan efisien juga menggunakan xargs:

    find [whatever] -print0 | xargs -0 cat
    

    The -print0bendera mengatakan finduntuk menggunakan \0(null karakter) pembatas antara nama file, dan -0bendera mengatakan xargsuntuk mengharapkan ini \0pembatas. Ini memiliki perilaku yang hampir sama dengan pendekatan -exec... +, meskipun lebih portabel (tapi sayangnya lebih bertele-tele).

Laurence Gonsalves
sumber
Metode backtick sangat bagus, karena ia bekerja untuk perintah lain lsjuga.
Martin Braun
@ Martin Braun menggunakan $()Juga bekerja dengan perintah selain find .
Laurence Gonsalves
Terima kasih, baik untuk mengetahui, saya agak berhenti membaca setelah (1), karena ini melayani kebutuhan saya, karena saya tidak berurusan dengan karakter khusus seperti spasi dan semacamnya.
Martin Braun
9

Untuk mencapai ini (menggunakan bash) saya akan lakukan sebagai berikut:

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

Ini dikenal sebagai "substitusi perintah" dan strip feed default, yang benar-benar nyaman!

info lebih lanjut di sini

Stphane
sumber
6

Kedengarannya seperti pekerjaan untuk skrip shell bagi saya:

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

atau semacam itu

Gandalf
sumber
2
Ini adalah jawaban yang valid, meski belum tentu optimal, untuk pertanyaan itu.
Jonathan Leffler
1
... ya tapi itu bagus jika Anda ingin satu file besar dengan nama file terdaftar juga.
ʍǝɥʇɐɯ
1
Saya suka ini yang terbaik. Blok loop seperti ini menyisakan ruang untuk melakukan hal-hal lain.
kakyo
4

Inilah cara saya untuk menemukan nama file yang mengandung beberapa konten yang saya minati, hanya satu baris bash yang dengan baik menangani spasi di nama file juga:

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

Saya menggunakan sesuatu seperti ini:

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

" -print0" argumen untuk "find" dan " -0" argumen untuk "xargs" diperlukan untuk menangani spasi putih di jalur / nama file dengan benar.

ekinak
sumber
2

Perintah find memiliki argumen -exec yang dapat Anda gunakan untuk hal-hal seperti ini, Anda bisa melakukan grep secara langsung menggunakan itu.

Misalnya ( dari sini, contoh bagus lainnya di halaman ini ):

find . -exec grep "www.athabasca" '{}' \; -print 
Chad Birch
sumber
2

Ini foto saya untuk penggunaan umum:

grep YOURSTRING `find .`

Ini akan mencetak nama file

Zakki
sumber
2

Dalam bash, berikut ini akan sesuai:

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

Ini akan menemukan semua file di /dirdirektori, dan memasukkan nama file xargsdengan aman, yang akan dikendarai dengan aman grep.

Melewati xargsbukanlah ide yang baik jika Anda memiliki ribuan file /dir; catakan rusak karena panjang daftar argumen yang berlebihan. xargsakan menyelesaikan semua itu untuk Anda.

The -print0argumen untuk findjerat dengan -0argumen untuk xargsmenangani nama file dengan spasi benar. The -iargumen untuk xargsmemungkinkan Anda untuk memasukkan nama file di mana diperlukan dalam catbaris perintah. Tanda kurung diganti dengan nama file yang disalurkan ke catperintah dari find.

McClain Looney
sumber
0

Ini bekerja untuk saya

find _CACHE_* | while read line; do
    cat "$line" | grep "something"
done
Steven Penny
sumber
0

Gunakan ggrep .

ggrep -H -R -I "mysearchstring" *

untuk mencari file di unix yang mengandung teks yang terletak di direktori saat ini atau subdirektori

Bawah
sumber
0

Ini akan mencetak nama dan isi file-hanya secara rekursif ..

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

Edit (Versi yang ditingkatkan): Ini akan mencetak nama dan isi file teks (ascii) saja secara rekursif ..

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

Satu upaya lagi

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

Apakah Anda mencoba menemukan teks dalam file? Anda cukup menggunakan grep untuk itu ...

grep searchterm *
Scott Anderson
sumber
-1

Untuk membuat daftar dan melihat isi semua file abc.def pada server di direktori / ghi dan / jkl

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

Untuk membuat daftar file abc.def yang telah mengomentari entri dan tampilan, lihat entri tersebut di direktori / ghi dan / jkl

find /ghi /jkl -type f -name abc.def 2> /dev/null -exec grep -H ^# {} \;
Sharjeel
sumber