Membungkus perintah yang menyertakan tanda kutip tunggal dan ganda untuk perintah lain

10

Baru-baru ini saya belajar tentang menonton , tetapi saya kesulitan membuatnya bekerja dengan perintah yang relatif canggih.

Sebagai contoh, saya ingin meminta watchuntuk menjalankan perintah berikut zshsetiap tiga detik * :

for x in `command_1 | grep keyword | cut -d' ' -f1`; do command_2 "word[word=number]" $x; done

seperti yang Anda lihat baris di atas termasuk tanda kutip tunggal, tanda kutip ganda, di antara karakter khusus lainnya.

Jadi saya mencoba:

watch -n 3 "for x in `my_command | grep keyword | cut -d' ' -f1`; do command2 "rusage[mem=7000]" $x; done"

tapi kemudian saya mendapat:

tidak ditemukan kecocokan untuk x in! @ # $ # ....; selesai

Saya mencoba kombinasi lain tanpa hasil. Ini salah satu dari usaha itu:

watch -n 3 "for x in $(bjobs -w | grep pre_seg | cut -d' ' -f1); do bmod -R "rusage[mem=7000]" $x; done"

yang juga menghasilkan kesalahan serupa.

Ada ide bagaimana membuat ini bekerja?


* Saya juga akan tertarik dengan solusi yang berhasilbash

Amelio Vazquez-Reina
sumber

Jawaban:

16

Kiat umum: jika Anda memiliki dua tingkat sarang, hindari menggunakan tanda kutip tunggal pada perintah dalam, dan gunakan tanda kutip tunggal di sekitar perintah luar.

Kiat tambahan: jangan gunakan backticks - `…` - untuk menjalankan kode, alih-alih gunakan $(…)di sekitarnya. Dollar-tanda kurung adalah DWIM ('Lakukan apa yang saya maksudkan') dalam hal kutipan bersarang; backquotes memiliki aturan-aturan misterius yang bergantung pada shell.

watch -n 3 'for x in $(my_command | grep keyword | cut -d" " -f1); do command2 "rusage[mem=7000]" "$x"; done'

Jika Anda membutuhkan tanda kutip tunggal di dalam perintah kutip tunggal, Anda dapat menggunakan '\''. Pikirkan keempat karakter ini sebagai cara untuk mengutip satu kutipan di dalam satu tanda kutip, meskipun secara teknis ini dibangun sebagai akhir dari string yang dikutip tunggal, menambahkan kutipan tunggal secara literal, dan memulai string kutipan tunggal yang baru (masih ditambahkan ke kata saat ini).

Untuk kasus yang lebih kompleks, hitunglah kutipan dengan susah payah, atau tentukan variabel sementara.

cmd='for x in $(my_command | grep keyword | cut -d" " -f1); do command2 "rusage[mem=7000]" "$x"; done'
watch_cmd='watch -n 3 "$cmd"'

Jawaban ini tidak spesifik untuk zsh. Zsh tidak membawa apa pun yang utama di sini. Anda dapat menyimpan sedikit kutipan karena tidak perlu tanda kutip ganda di sekitar penggantian perintah, dan kadang-kadang ada cara untuk menggunakan perintah bawaan daripada perintah eksternal yang mengurangi kebutuhan kutipan, tetapi masalah yang mendasarinya sama seperti di shell lain.

Oh, dan omong-omong, perhatikan bahwa watchakan menjalankan perintah Anda di sh, bukan di zsh. Jika Anda ingin menjalankan perintah di zsh, Anda harus menjalankannya

watch -n 3 -x zsh -c "$cmd"

pada Debian / Ubuntu, dan

export cmd
watch -n 3 'exec zsh -c "$cmd"'

(bahkan lebih banyak mengutip!) di tempat lain.

Gilles 'SANGAT berhenti menjadi jahat'
sumber
Terima kasih @Gilles. Itu sangat membantu. Menariknya watchtidak datang dengan opsi -xmaupun -cpada mesin saya. Saya mencarinya online dan belum menemukan halaman manual yang menyebutkannya. Apa yang dilakukan opsi ini?
Amelio Vazquez-Reina
1
@intrpc -xmemberitahu watchuntuk tidak melewati perintah melalui shell. Saya baru tahu bahwa ini khusus untuk Debian / Ubuntu, meskipun tidak diindikasikan demikian. Itu -cditeruskan ke zsh, bukan ke watch.
Gilles 'SO- stop being evil'
@Gilles Opsi -xdan -execkeduanya ada di watch(pada gentoo) saya, jadi ini jelas bukan Debian-spesifik. Mungkin Anda dibandingkan dengan beberapa versi lain watch? Milik saya berasal dari paket procps .
rozcietrzewiacz
1
@rozcietrzewiacz juga watchberasal dari procpsDebian. Sumber resmi tidak ada --exec. Paket di Debian (dan turunannya termasuk Ubuntu) menambahkan opsi dalam tambalan khusus-Debian ( watch_exec_beep.patch; ini adalah "Mortys watch exec patch" dari bug # 410967 ). Gentoo mungkin telah mengadopsi tambalan yang serupa.
Gilles 'SO- stop being evil'