it-swarm-id.com

Jalankan perintah sekali per baris input pipa?

Saya ingin menjalankan perintah Java sekali untuk setiap kecocokan ls | grep pattern -. Dalam hal ini, saya pikir saya bisa melakukan find pattern -exec Java MyProg '{}' \; tapi saya ingin tahu tentang kasus umum - apakah ada cara mudah untuk mengatakan "jalankan perintah sekali untuk setiap baris input standar"? (Dalam ikan atau bash.)

176
Xodarap

Itulah yang xargs lakukan.

... | xargs command
98
Keith

Jawaban yang diterima memiliki ide yang tepat, tetapi kuncinya adalah lulus xargs the -n1 switch, yang berarti "Jalankan perintah sekali per baris output:"

cat file... | xargs -n1 command

Atau, untuk satu file input Anda dapat menghindari pipa dari cat seluruhnya dan hanya pergi dengan:

<file xargs -n1 command
193

Di Bash atau Shell gaya Bourne lainnya (abu, ksh, zsh, ...):

while read -r line; do command "$line"; done

read -r membaca satu baris dari input standar (read tanpa -r mengartikan garis miring terbalik, Anda tidak menginginkannya). Dengan demikian Anda dapat melakukan salah satu dari yang berikut:

$ command | while read -r line; do command "$line"; done  

$ while read -r line; do command "$line"; done <file
117
Steven D

Saya setuju dengan Keith, xargs adalah alat paling umum untuk pekerjaan itu.

Saya biasanya menggunakan pendekatan 3 langkah.

  • lakukan hal-hal dasar sampai Anda memiliki sesuatu yang ingin Anda kerjakan
  • siapkan baris dengan awk sehingga mendapat sintaks yang benar
  • lalu biarkan xargs menjalankannya, mungkin dengan bantuan bash.

Ada cara yang lebih kecil dan lebih cepat, tetapi cara ini hampir selalu berhasil.

Contoh sederhana:

ls | 
grep xls | 
awk '{print "MyJavaProg --arg1 42 --arg2 "$1"\0"}' | 
xargs -0 bash -c

2 baris pertama memilih beberapa file untuk dikerjakan, kemudian awk menyiapkan string Nice dengan perintah untuk dieksekusi dan beberapa argumen dan $ 1 adalah input kolom pertama dari pipa. Dan akhirnya saya memastikan bahwa xargs mengirimkan string ini ke bash yang baru saja menjalankannya.

Ini sedikit berlebihan, tetapi resep ini telah membantu saya di banyak tempat karena sangat fleksibel.

22
Johan

GNU Parallel dibuat untuk tugas semacam itu. Penggunaan paling sederhana adalah:

cat stuff | grep pattern | parallel Java MyProg

Tonton video intro untuk mempelajari lebih lanjut: http://www.youtube.com/watch?v=OpaiGYxkSuQ

15
Ole Tange

Juga, while read loop dalam Shell ikan (saya berasumsi Anda ingin Shell ikan, mengingat Anda menggunakan ikan tag).

command | while read line
    command $line
end

Beberapa poin yang perlu diperhatikan.

  • read tidak menerima -r argumen, dan itu tidak menginterpretasikan backslash Anda, untuk membuat use case yang paling umum mudah.
  • Anda tidak perlu mengutip $line, tidak seperti bash, ikan tidak memisahkan variabel dengan spasi.
  • command dengan sendirinya adalah kesalahan sintaks (untuk menangkap penggunaan argumen placeholder seperti itu). Ganti dengan perintah asli.
10
Konrad Borowski

Ketika berhadapan dengan input yang berpotensi tidak bersih, saya suka melihat seluruh pekerjaan 'terbilang' baris demi baris untuk inspeksi visual sebelum saya menjalankannya (terutama ketika sesuatu yang merusak seperti membersihkan kotak surat orang).

Jadi yang saya lakukan adalah membuat daftar parameter (mis. Nama pengguna), memasukkannya ke file dengan mode satu-catatan-per-baris, seperti ini:

johndoe  
jamessmith  
janebrown  

Kemudian saya membuka daftar di vim, dan memotongnya dengan pencarian dan ganti ekspresi sampai saya mendapatkan daftar perintah lengkap yang perlu dieksekusi, seperti ini:

/bin/rm -fr /home/johndoe  
/bin/rm -fr /home/jamessmith 

Dengan cara ini jika regex Anda tidak lengkap, Anda akan melihat perintah apa yang akan memiliki masalah potensial (mis. /bin/rm -fr johnnyo connor). Dengan cara ini Anda dapat membatalkan regex Anda, dan coba lagi dengan versi yang lebih andal. Nama mangling terkenal karena hal ini, karena sulit untuk mengurus semua kasus Edge seperti Van Gogh, O'Connors, St. Clair, Smith-Wesson.

Memiliki set hlsearch berguna untuk melakukan ini dalam vim, karena akan menyorot semua kecocokan, sehingga Anda dapat dengan mudah melihat jika tidak cocok, atau cocok dengan cara yang tidak disengaja.

Setelah regex Anda sempurna dan menangkap semua case yang dapat Anda uji/pikirkan, maka saya biasanya mengonversinya menjadi ekspresi sed sehingga dapat sepenuhnya otomatis untuk dijalankan lagi.

Untuk kasus di mana jumlah baris input mencegah Anda melakukan inspeksi visual, saya sangat menyarankan untuk mengulangi perintah ke layar (atau lebih baik lagi, log) sebelum dijalankan, jadi jika kesalahan keluar, Anda tahu persis perintah mana yang menyebabkan itu gagal. Kemudian Anda dapat kembali ke regex asli dan menyesuaikannya sekali lagi.

1
Marcin

Di sini, copypaste Anda dapat langsung digunakan:

cat list.txt | xargs -I{} command parameter {} parameter

Item dari daftar akan diletakkan di tempat {} berada dan seluruh perintah dan parameter akan digunakan apa adanya.

1
DustWolf

Ini dimungkinkan dengan xargs, seperti yang ditunjukkan oleh jawaban lain. Kita perlu membedakan dua spesifik di bagian "sekali per baris" dari pertanyaan:

  1. Sekali: Gunakan -n 1, ini memastikan bahwa perintah dipanggil tepat sekali untuk setiap argumen. Namun, secara default, xargs mengasumsikan bahwa argumen dibatasi oleh spasi - ini akan pecah begitu file berisi spasi.
  2. Per baris: Gunakan -d '\n', atau preprocess input dengan tr '\n' '\0' dan gunakan -0. Ini membuat perintah kuat terhadap spasi di input.

Baris perintah terakhir kemudian menjadi:

.... | xargs -n 1 -d '\n' <command>

atau (dengan tr)

.... | tr '\n' '\0' | xargs -n 1 -0 <command>

Jika perintah Anda dapat memproses beberapa argumen sekaligus (seperti grep atau sed), Anda dapat menghilangkan -n 1 untuk mempercepat operasi dalam banyak kasus.

0
krlmlr

Jika suatu program mengabaikan pipa tetapi menerima file sebagai argumen, maka Anda bisa mengarahkannya ke file khusus /dev/stdin.

Saya tidak terbiasa dengan Java, tetapi berikut ini adalah contoh bagaimana Anda akan melakukannya untuk bash:

$ echo $'pwd \n cd / \n pwd' |bash /dev/stdin
/home/rolf
/

$ Diperlukan untuk menerjemahkan bash \n ke baris baru. Saya tidak yakin mengapa.

0
Rolf

Saya lebih suka ini - memungkinkan perintah multi-line dan menghapus kode

find -type f -name filenam-pattern* | while read -r F
do
  echo $F
  cat $F | grep 'some text'
done

ref https://stackoverflow.com/a/3891678/248616

0
Nam G VU