Pilihan ada padamu. Jika Anda tidak mengutip $@
salah satu nilainya, perluas ekspansi dan interpretasi tambahan. Jika Anda mengutipnya semua argumen yang dilewati, fungsi tersebut direproduksi dalam perluasannya kata demi kata. Anda tidak akan pernah dapat menangani token sintaksis shell secara andal seperti &>|
dan lain-lain dengan cara apa pun tanpa menguraikan argumen sendiri - dan karenanya Anda memiliki pilihan yang lebih masuk akal untuk menyerahkan fungsi Anda, salah satunya:
- Tepat kata-kata yang digunakan dalam pelaksanaan satu perintah sederhana dengan
"$@"
.
...atau...
- Versi argumen Anda yang diperluas dan ditafsirkan lebih lanjut yang kemudian diterapkan bersama sebagai perintah sederhana
$@
.
Tidak ada cara yang salah jika disengaja dan jika efek dari apa yang Anda pilih dipahami dengan baik. Kedua cara memiliki keunggulan satu di atas yang lain, meskipun keunggulan yang kedua jarang bermanfaat. Masih...
(run_this(){ $@; }; IFS=@ run_this 'ls@-dl@/tmp')
drwxrwxrwt 22 root root 660 Dec 28 19:58 /tmp
... tidak sia - sia , hanya saja jarang berguna . Dan dalam sebuah bash
shell, karena bash
tidak secara default menempel definisi variabel ke lingkungannya bahkan ketika definisi tersebut ditambahkan ke baris perintah dari builtin khusus atau ke suatu fungsi, nilai global untuk $IFS
tidak terpengaruh, dan deklarasi adalah lokal hanya untuk run_this()
panggilan.
Demikian pula:
(run_this(){ $@; }; set -f; run_this ls -l \*)
ls: cannot access *: No such file or directory
... globbing juga dapat dikonfigurasi. Kutipan melayani tujuan - mereka bukan untuk apa-apa. Tanpa mereka ekspansi shell mengalami interpretasi ekstra - interpretasi yang dapat dikonfigurasi . Dulu - dengan beberapa sangat tua kerang - yang $IFS
telah secara global diterapkan untuk semua masukan, dan bukan hanya ekspansi. Bahkan, kata shell berperilaku sangat seperti run_this()
dalam hal mereka memecahkan semua kata input pada nilai $IFS
. Jadi, jika yang Anda cari adalah perilaku shell yang sangat lama, maka Anda harus menggunakannya run_this()
.
Saya tidak mencarinya, dan saya agak kesulitan saat ini untuk memberikan contoh yang berguna. Saya biasanya lebih suka untuk perintah shell saya berjalan untuk menjadi yang saya ketik. Maka, diberi pilihan, saya hampir selalu run_that()
. Kecuali itu...
(run_that(){ "$@"; }; IFS=l run_that 'ls' '-ld' '/tmp')
drwxrwxrwt 22 root root 660 Dec 28 19:58 /tmp
Apa saja bisa dikutip. Perintah akan dijalankan dengan mengutip. Ini bekerja karena pada saat perintah itu benar-benar dijalankan, semua kata input telah mengalami penghapusan kutipan - yang merupakan tahap terakhir dari proses interpretasi input shell. Jadi perbedaan antara 'ls'
dan ls
hanya bisa berarti ketika shell sedang menerjemahkan - dan itulah sebabnya mengutip ls
memastikan bahwa setiap alias yang bernama ls
tidak diganti dengan ls
kata perintah yang saya kutip . Selain itu, satu-satunya hal yang mempengaruhi kutipan adalah pembatasan kata-kata (yang adalah bagaimana dan mengapa variabel / input-spasi putih mengutip bekerja) , dan interpretasi dari metakarakter dan kata-kata yang dicadangkan.
Begitu:
'for' f in ...
do :
done
bash: for: command not found
bash: do: unexpected token 'do'
bash: do: unexpected token 'done'
Anda tidak akan pernah bisa melakukan itu dengan salah satu run_this()
atau run_that()
.
Tetapi nama fungsi, atau $PATH
perintah, atau builtin akan mengeksekusi dengan baik dikutip atau tidak dikutip, dan itulah bagaimana run_this()
dan run_that()
bekerja di tempat pertama. Anda tidak akan dapat melakukan sesuatu yang bermanfaat dengan $<>|&(){}
semua itu. Singkatnya eval
, adalah.
(run_that(){ "$@"; }; run_that eval printf '"%s\n"' '"$@"')
eval
printf
"%s\n"
"$@"
Tetapi tanpa itu, Anda dibatasi pada batas-batas perintah sederhana berdasarkan kutipan yang Anda gunakan (bahkan ketika Anda tidak melakukannya karena $@
bertindak seperti kutipan pada awal proses ketika perintah diuraikan untuk karakter metakarakter) . Kendala yang sama berlaku untuk penugasan dan pengalihan baris perintah, yang terbatas pada baris perintah fungsi. Tapi itu bukan masalah besar:
(run_that(){ "$@";}; echo hey | run_that cat)
hey
Saya dapat dengan mudah <
mengarahkan ulang input atau >
output di sana seperti saya membuka pipa.
Pokoknya, secara berputar-putar, tidak ada cara yang benar atau salah di sini - setiap cara memiliki kegunaannya. Hanya saja Anda harus menulisnya saat Anda bermaksud menggunakannya, dan Anda harus tahu apa yang ingin Anda lakukan. Menghilangkan tanda kutip dapat memiliki tujuan - jika tidak akan ada tanda kutip sama sekali - tetapi jika Anda menghilangkannya karena alasan yang tidak relevan dengan tujuan Anda, Anda hanya menulis kode yang buruk. Lakukan apa yang Anda maksudkan; Saya tetap mencoba.
run_that
Perilaku pasti apa yang saya harapkan (bagaimana jika ada ruang di jalan menuju perintah?). Jika Anda menginginkan perilaku lain, tentunya Anda akan berhenti tanda kutip di situs- panggilan tempat Anda mengetahui data apa itu? Saya berharap untuk memanggil fungsi ini sebagairun_that ls -l
, yang berfungsi sama di kedua versi. Apakah ada kasus yang membuat Anda berharap berbeda?