Parameterkan panggilan berantai ke program utilitas di Bash


12

Saya memiliki program UNIX kotak hitam yang digunakan dalam shell Bash yang membaca kolom data dari stdin, memprosesnya (menerapkan efek smoothing) kemudian menghasilkan stdout. Saya menggunakannya oleh pipa UNIX, seperti

generate | smooth | plot  

Untuk lebih smoothing, saya bisa mengulangi smooth, jadi itu akan dipanggil dari baris perintah Bash sebagai

generate | smooth | smooth | plot   

atau bahkan

generate | smooth | smooth | smooth | smooth | smooth | smooth | smooth | smooth | smooth | smooth | plot

Ini semakin tidak sehat. Saya ingin membuat pembungkus Bash untuk dapat menyalurkan ke smoothdan memberi makan outputnya kembali ke instance baru smoothbeberapa kali, seperti

generate | newsmooth 5 | plot

dari pada

generate | smooth | smooth | smooth | smooth | smooth | plot

Upaya pertama saya adalah skrip Bash yang menghasilkan file temp di direktori saat ini dan menghapusnya, tetapi itu berubah jelek ketika saya tidak berada di direktori dengan akses tulis, dan juga meninggalkan file sampah ketika terganggu.

Tidak ada argumen untuk smoothprogram ini.

Apakah ada cara yang lebih elegan untuk "membungkus" program semacam itu untuk mengukur jumlah panggilan?


1
Saya harap teladan Anda adalah kasus yang dipaksakan demi pertanyaan dan bukan kebutuhan aktual
arielnmz

Jawaban:


18

Anda bisa membungkusnya dalam fungsi rekursif:

smooth() {
  if [[ $1 -gt 1 ]]; then # add another call to function
    command smooth | smooth $(($1 - 1)) 
  else
    command smooth # no further 
  fi
}

Anda akan menggunakan ini sebagai

generate | smooth 5 | plot

yang akan setara dengan

generate | smooth | smooth | smooth | smooth | smooth | plot

Ini sempurna, berperilaku persis seperti yang dibutuhkan. Dan sekarang saya belajar tentang kata kunci "perintah" bash.
Diane Wilbor

2
Kebetulan, ini adalah pendekatan yang sama yang saya gunakan di Bagaimana cara saya membuat kode rantai pipa yang panjang dan sewenang-wenang? - dan, jauh sebelum itu, dalam menangani daftar edit panjang di xmlstarlet .
Charles Duffy

5

Jika Anda mampu mengetikkan koma sebanyak jumlah smoothperintah yang Anda inginkan, Anda dapat mengambil keuntungan dari Brace Expansion yang dipisahkan oleh koma shell.

TL; DR

Seluruh baris perintah untuk case sampel Anda adalah:

generate | eval 'smooth |'{,,,,} plot

catatan:

  • tambahkan atau hapus koma jika Anda ingin pengulangan lebih atau lebih sedikit smooth |
  • tidak ada |sebelumnya plotkarena itu termasuk yang terakhirsmooth | string diproduksi oleh Brace Expansion
  • Anda juga dapat memberikan argumen smooth, selama Anda dapat memasukkannya dengan benar di dalam bagian tetap yang dikutip yang mendahului kurung kurawal terbuka; dalam hal apa pun ingat bahwa Anda akan memberikan mereka untuk semua pengulangan perintah

Bagaimana itu bekerja

Ekspansi Brace yang dipisahkan dengan koma memungkinkan Anda untuk menghasilkan string secara dinamis, masing-masing terbuat dari bagian tetap yang ditentukan ditambah bagian variabel yang ditentukan. Ini menghasilkan string sebanyak ada bagian variabel yang ditunjukkan, sepertia{b,c,d} menghasilkan ab ac ad.

Trik kecil di sini adalah bahwa jika Anda lebih suka membuat daftar bagian variabel kosong , yaitu dengan hanya koma di dalam kurung kurawal, Brace Expansion hanya akan menghasilkan salinan dari bagian tetap saja. Contohnya:

smooth{,,,,}

akan menghasilkan:

smooth smooth smooth smooth smooth

Perhatikan bahwa 4 koma menghasilkan 5smooth string. Itulah cara kerja Brace Expansion ini: menghasilkan string sebanyak koma ditambah satu.

Tentu saja dalam kasus Anda, Anda juga perlu |memisahkan masing-masing smooth, jadi tambahkan saja di bagian tetap tetapi berhati-hatilah untuk mengutipnya dengan benar agar shell tidak menafsirkannya sekaligus. Itu adalah:

'smooth|'{,,,,}

akan menghasilkan:

'smooth|' 'smooth|' 'smooth|' 'smooth|' 'smooth|'

Berhati-hatilah selalu menempatkan bagian tetap yang berbatasan langsung dengan brace terbuka, yaitu tidak ada ruang antara ' dan {.

(Perhatikan juga bahwa untuk membentuk bagian tetap, Anda juga dapat menggunakan tanda kutip ganda dan bukan tanda kutip tunggal, jika Anda perlu memperluas variabel shell di bagian tetap. Hanya berhati-hati dengan pelolosan ekstra yang diperlukan saat karakter khusus beberapa shell muncul di dalam string yang dikutip ganda).

Pada titik ini Anda perlu eval diterapkan ke string itu untuk membuat shell akhirnya menafsirkannya sebagai perintah pipelined seharusnya.

Jadi, untuk menjumlahkan semuanya, seluruh baris perintah untuk case sampel Anda adalah:

generate | eval 'smooth |'{,,,,} plot

1
Ada masalah keamanan yang signifikan jika ini digunakan di tempat-tempat di mana panggilan itu diparameterisasi. Lihat jawaban saya tentang fungsi bash Rekursif vs bangunan string "eval" berulang: Mana yang berkinerja lebih baik? lebih pada Stack Overflow.
Charles Duffy

1
@CharlesDuffy Saya sepenuhnya setuju dengan kekhawatiran Anda tentang risiko tersirat dalam penggunaan evalsaat seseorang memberikan string yang tidak tepercaya, tidak disanitasi, untuk dievaluasi, yaitu saat digunakan dengan variabel yang dapat membawa konten "tidak dikenal" seperti kasus yang Anda tautkan. Di sisi lain, evalbisa juga sangat berguna untuk "plumbing" perintah yang cepat, terutama ketika digunakan pada prompt, seperti halnya case yang ada, di mana evalinput hanya berupa string literal yang diketik secara manual oleh pengguna di orang
LL3

Seperti yang sudah terlihat di tempat lain, Anda selalu bisa mengganti eval strdengan sesuatu yang sok & bodoh . /dev/stdin <<<str. Tidak hanya akan membuat kesan pada orang bodoh, itu juga akan menjaga @CharlesDuffy dari punggung Anda ;-)
pizdelect

1
@pizdelect, Anda dapat membaca komentar sebelumnya LL3 dengan hati-hati - seimbang, bernuansa, dan bijaksana. (Memang, komentar awal saya sendiri memiliki nuansa yang tampaknya Anda abaikan; "jika digunakan dalam kasus di mana panggilan parameterisasi" adalah perbedaan penting: turunan LL3 tidak parameter, membuatnya aman).
Charles Duffy
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.