Bagaimana cara saya memasukkan pipa | di linux find -exec perintah saya?

220

Ini tidak berfungsi. Bisakah ini dilakukan dalam pencarian? Atau apakah saya perlu xargs?

find -name 'file_*' -follow -type f -exec zcat {} \| agrep -dEOE 'grep' \;
beberapa pria
sumber

Jawaban:

145

Tugas menafsirkan simbol pipa sebagai instruksi untuk menjalankan banyak proses dan menyalurkan output dari satu proses ke input proses lain adalah tanggung jawab shell (/ bin / sh atau yang setara).

Dalam contoh Anda, Anda dapat memilih untuk menggunakan shell tingkat atas untuk melakukan pemipaan seperti:

find -name 'file_*' -follow -type f -exec zcat {} \; | agrep -dEOE 'grep'

Dalam hal efisiensi, hasil ini membutuhkan satu doa penemuan, banyak doa zcat, dan satu doa agrep.

Ini hanya akan menghasilkan satu proses agrep tunggal yang akan memproses semua output yang dihasilkan oleh banyak doa zcat.

Jika karena alasan tertentu ingin memohon agrep beberapa kali, Anda dapat melakukan:

find . -name 'file_*' -follow -type f \
    -printf "zcat %p | agrep -dEOE 'grep'\n" | sh

Ini membangun daftar perintah menggunakan pipa untuk mengeksekusi, kemudian mengirimkan ini ke shell baru untuk benar-benar dieksekusi. (Menghilangkan "| sh" terakhir adalah cara yang bagus untuk men-debug atau menjalankan perintah-perintah kering seperti ini.)

Dalam hal efisiensi, hasil ini membutuhkan satu doa penemuan, satu doa sh, banyak doa zcat dan banyak doa agrep.

Solusi paling efisien dalam hal jumlah permintaan perintah adalah saran dari Paul Tomblin:

find . -name "file_*" -follow -type f -print0 | xargs -0 zcat | agrep -dEOE 'grep'

... yang meminta satu doa penemuan, satu doa xargs, beberapa doa zcat dan satu doa agrep.

Rolf W. Rasmussen
sumber
1
Keuntungan lain dari xargs adalah, bahwa Anda dapat mempercepatnya dengan cpu multi-core modern bahkan lebih maju, dengan menggunakan sakelar -P (-P 0).
flolo
Ya, -P swich memang cara yang bagus untuk mempercepat eksekusi secara umum. Sayangnya, Anda menjalankan risiko output dari proses paralel zcat yang disalurkan ke agrep interleaved, yang akan mempengaruhi hasilnya. Efek ini dapat didemonstrasikan menggunakan: echo -e "1 \ n2" | xargs -P 0 -n 1 ya | uniq
Rolf W. Rasmussen
@ Adam, saya telah membuat perubahan yang Anda sarankan.
Paul Tomblin
di mana Anda dapat menginstal perintah xjobs yang luar biasa (berasal dari Solaris)
sehe
4
Jawaban sederhana dan lebih umum di stackoverflow.com/a/21825690/42973 : -exec sh -c "… | … " \;.
Eric O Lebigot
278

solusinya mudah: jalankan via sh

... -exec sh -c "zcat {} | agrep -dEOE 'grep' " \;
flolo
sumber
17
Apa yang ingin dicapai OP dapat dipenuhi dengan saran-saran di atas, tetapi inilah yang sebenarnya menjawab pertanyaan yang diajukan. Ada alasan untuk melakukannya dengan cara ini - exec jauh lebih kuat daripada hanya beroperasi pada file yang dikembalikan oleh find, terutama ketika dikombinasikan dengan tes. Misalnya: temukan geda-gaf / -type d -exec bash -c 'DIR = {}; [[$ (temukan $ DIR -maxdepth 1 | xargs grep -i rempah | wc -l) -ge 5]] && echo $ DIR '\; Akan mengembalikan semua direktori di jalur pencarian yang berisi lebih dari 5 baris total di antara semua file di direktori itu yang mengandung kata rempah
swarfrat
3
Jawaban Terbaik. Grepping seluruh output (seperti jawaban lain menyarankan) tidak sama dengan grep setiap file. Kiat: alih-alih sh, Anda dapat menggunakan shell lain yang Anda inginkan (saya mencobanya dengan bash dan itu berjalan ok).
pagliuca
1
Pastikan untuk tidak mengabaikan -copsi. Kalau tidak, Anda akan mendapatkan No such file or directorypesan kesalahan yang membingungkan .
asmaier
inilah pengganti ps yang hebat yang menggunakan find dengan memipipkan di dalam shell exec: / usr / bin / find / proc -mindepth 1 -maxdepth 1 -type d -regex '. * / [0-9] +' - cetak -exec bash -c "cat {} / cmdline | tr '\\ 0' ''; echo" \;
parity3
1
Contoh menemukan file dan mengganti nama mereka dengan sed menggunakan ekspresi reguler find -type f -name '*.mdds' -exec sh -c "echo {} | sed -e 's/_[0-9]\+//g' | xargs mv {}" \;
Rostfrei
16
find . -name "file_*" -follow -type f -print0 | xargs -0 zcat | agrep -dEOE 'grep'
Paul Tomblin
sumber
Berharap untuk menghindari -cetak dan xargs untuk alasan efisiensi. Mungkin itu benar-benar masalah saya: find tidak dapat menangani perintah melalui -exec
someguy
Ini tidak berfungsi dengan file dengan spasi di namanya; untuk memperbaikinya, ganti -print dengan -print0 dan tambahkan opsi -0 ke xargs
Adam Rosenfield
2
@someguy - Wha? Menghindari xarg karena alasan efisiensi? Memanggil satu instance dari zcat, dan mengirimkannya daftar beberapa file, jauh lebih efisien daripada mengeksekusi instance baru untuk setiap file yang ditemukan.
Sherm Pendley
@ Adam - Saya telah membuat perubahan yang disarankan. 99% dari waktu ketika saya melakukan penemuan, ada di direktori kode sumber saya, dan tidak ada file di sana memiliki ruang jadi saya tidak repot-repot dengan print0. Sekarang direktori dokumen saya, saya ingat print0.
Paul Tomblin
10

Anda juga dapat mem-pipe ke whileloop yang dapat melakukan banyak tindakan pada file yang ditemukan find. Jadi di sini adalah satu untuk mencari di jararsip untuk file kelas java yang diberikan dalam folder dengan distro jarfile yang besar

find /usr/lib/eclipse/plugins -type f -name \*.jar | while read jar; do echo $jar; jar tf $jar | fgrep IObservableList ; done

titik kuncinya adalah bahwa whileloop berisi beberapa perintah yang merujuk nama file yang diteruskan dipisahkan oleh tanda koma dan perintah-perintah ini dapat termasuk pipa. Jadi dalam contoh itu saya gema nama file yang cocok kemudian daftar apa yang ada di pemfilteran arsip untuk nama kelas yang diberikan. Outputnya terlihat seperti:

/usr/lib/eclipse/plugins/org.eclipse.core.contenttype.source_3.4.1.R35x_v20090826-0451.jar /usr/lib/eclipse/plugins/org.eclipse.core.databinding.observable_1.2.0.M20090902-0800 .jar org / eclipse / core / databinding / observable / list / IObservableList .class /usr/lib/eclipse/plugins/org.eclipse.search.source_3.5.1.r351_v20090708-0800.jar / usr / lib / eclipse / plugins / org.eclipse.jdt.apt.core.source_3.3.202.R35x_v20091130-2300.jar /usr/lib/eclipse/plugins/org.eclipse.cvs.source_1.0.400.v201002111343.jar / usr / lib / eclipse / plugins / org.eclipse.help.appserver_3.1.400.v20090429_1800.jar

di bash shell saya (xubuntu10.04 / xfce) itu benar-benar membuat nama kelas yang cocok dicetak tebal sebagai fgrephighlight pada string yang cocok; ini membuatnya sangat mudah untuk memindai daftar ratusan jarfile yang dicari dan dengan mudah melihat kecocokan.

pada windows Anda dapat melakukan hal yang sama dengan:

for /R %j in (*.jar) do @echo %j & @jar tf %j | findstr IObservableList

perhatikan bahwa pada windows pemisah perintah adalah '&' tidak ';' dan bahwa '@' menahan gema perintah untuk memberikan output yang rapi seperti linux find output di atas; meskipun findstrtidak membuat string yang cocok jadi Anda harus melihat sedikit lebih dekat pada output untuk melihat nama kelas yang cocok. Ternyata perintah windows 'untuk' tahu beberapa trik seperti perulangan melalui file teks ...

Nikmati

simbo1905
sumber
2

Saya menemukan bahwa menjalankan perintah string shell (sh -c) berfungsi paling baik, misalnya:

find -name 'file_*' -follow -type f -exec bash -c "zcat \"{}\" | agrep -dEOE 'grep'" \;
Andrew Khoury
sumber
0

Jika Anda mencari alternatif sederhana, ini bisa dilakukan menggunakan loop:

for i in $(find -name 'file_*' -follow -type f);do zcat $i | agrep -dEOE 'grep');done

atau, bentuk yang lebih umum dan mudah dipahami:

for i in $(YOUR_FIND_COMMAND);do YOUR_EXEC_COMMAND_AND_PIPES );done

dan ganti {} dengan $ i di YOUR_EXEC_COMMAND_AND_PIPES

Louis Gagnon
sumber