Saya ingin menginisialisasi beberapa string di bagian atas skrip saya dengan variabel yang belum ditetapkan, seperti:
str1='I went to ${PLACE} and saw ${EVENT}'
str2='If you do ${ACTION} you will ${RESULT}'
dan kemudian nanti PLACE
, EVENT
, ACTION
, dan RESULT
akan ditetapkan. Saya ingin kemudian dapat mencetak string saya dengan variabel yang diperluas. Apakah satu-satunya pilihan saya eval
? Ini sepertinya berhasil:
eval "echo ${str1}"
apakah standar ini? apakah ada cara yang lebih baik untuk melakukan ini? Akan lebih baik untuk tidak menjalankan eval
mengingat variabel bisa menjadi apa saja.
Ketika saya mengerti maksud Anda, saya tidak percaya bahwa salah satu dari jawaban ini benar.
eval
tidak perlu dengan cara apa pun, Anda juga tidak perlu bahkan dua kali mengevaluasi variabel Anda.Memang benar, @Gilles sangat dekat, tetapi dia tidak membahas masalah kemungkinan nilai-nilai utama dan bagaimana mereka harus digunakan jika Anda membutuhkannya lebih dari sekali. Lagi pula, templat harus digunakan lebih dari sekali, bukan?
Saya pikir ini lebih merupakan urutan di mana Anda mengevaluasi mereka yang penting. Pertimbangkan yang berikut ini:
TERATAS
Di sini Anda akan menetapkan beberapa default dan bersiap untuk mencetaknya saat dipanggil ...
TENGAH
Di sinilah Anda mendefinisikan fungsi lain untuk memanggil fungsi cetak Anda berdasarkan hasil mereka ...
BAWAH
Anda telah menyiapkan semuanya sekarang, jadi di sinilah Anda akan menjalankan dan menarik hasil Anda.
HASIL
Saya akan membahas mengapa suatu saat, tetapi menjalankan di atas menghasilkan hasil sebagai berikut:
BAGAIMANA ITU BEKERJA:
Fitur utama di sini adalah konsep
conditional ${parameter} expansion.
Anda dapat mengatur variabel ke nilai hanya jika tidak disetel atau null menggunakan formulir:Jika Anda hanya ingin menetapkan variabel yang tidak disetel, Anda akan menghilangkan
:colon
dan nilai-nilai nol akan tetap apa adanya.TENTANG RUANG LINGKUP:
Anda mungkin memperhatikan bahwa dalam contoh di atas
$PLACE
dan$RESULT
diubah ketika diatur melaluiparameter expansion
meskipun_top_of_script_pr()
telah dipanggil, mungkin pengaturan mereka ketika dijalankan. Alasan karya ini adalah bahwa_top_of_script_pr()
adalah( subshelled )
fungsi - Saya sertakan dalamparens
daripada{ curly braces }
yang digunakan untuk orang lain. Karena itu disebut dalam subkulit, setiap variabel yang disetel adalahlocally scoped
dan saat ia kembali ke shell induknya, nilai-nilai itu menghilang.Tetapi ketika
_more_important_function()
set$ACTION
ituglobally scoped
begitu mempengaruhi_less_important_function()'s
evaluasi kedua$ACTION
karena_less_important_function()
set$ACTION
hanya melalui${parameter:=expansion}.
:BATAL
Dan mengapa saya menggunakan
:colon?
Yah terkemuka ,man
halaman akan memberitahu Anda bahwa: does nothing, gracefully.
Anda lihat,parameter expansion
persis seperti apa kedengarannya - ituexpands
dengan nilai${parameter}.
Jadi ketika kita mengatur variabel dengan${parameter:=expansion}
kita pergi dengan nilainya - yang shell akan upaya untuk mengeksekusi in-line. Jika ia mencoba menjalankannya,the cemetery
ia hanya akan meludahkan beberapa kesalahan pada Anda.PLACE="${PLACE:="the cemetery"}"
akan menghasilkan hasil yang sama, tetapi juga berlebihan dalam hal ini dan saya lebih suka shell: ${did:=nothing, gracefully}.
Itu memungkinkan Anda untuk melakukan ini:
DI SINI-DOKUMEN
Dan omong-omong - definisi in-line dari variabel nol atau tidak disetel juga mengapa yang berikut ini berfungsi:
Cara terbaik untuk memikirkan
here-document
adalah sebagai file aktual yang dialirkan ke file-deskriptor input. Kurang lebih seperti itu, tetapi cangkang yang berbeda menerapkannya sedikit berbeda.Dalam kasus apa pun, jika Anda tidak mengutip,
<<LIMITER
Anda dapat mengalirkannya dan mengevaluasi untukexpansion.
Jadi mendeklarasikan variabel dalam sebuahhere-document
can dapat berfungsi, tetapi hanya melaluiexpansion
yang membatasi Anda untuk menetapkan hanya variabel yang belum ditetapkan. Namun, itu sangat sesuai dengan kebutuhan Anda seperti yang telah Anda gambarkan, karena nilai default Anda akan selalu ditetapkan ketika Anda memanggil fungsi cetak template Anda.KENAPA TIDAK
eval?
Nah, contoh yang saya sajikan memberikan cara yang aman dan efektif untuk menerima
parameters.
Karena menangani ruang lingkup, setiap variabel dalam set via${parameter:=expansion}
dapat didefinisikan dari luar. Jadi, jika Anda meletakkan semua ini dalam skrip yang disebut template_pr.sh dan jalankan:Anda akan mendapatkan:
Ini tidak akan berfungsi untuk variabel-variabel yang secara harfiah diatur dalam skrip, seperti
$EVENT, $ACTION,
dan$one,
tetapi saya hanya mendefinisikan mereka dengan cara itu untuk menunjukkan perbedaannya.Dalam kasus apa pun, penerimaan input yang tidak diketahui ke dalam suatu
evaled
pernyataan pada dasarnya tidak aman, sedangkanparameter expansion
secara khusus dirancang untuk melakukannya.sumber
Anda bisa menggunakan placeholder untuk templat string alih-alih variabel yang tidak diperluas. Ini akan cepat berantakan. Jika apa yang Anda lakukan sangat template berat, Anda mungkin ingin mempertimbangkan bahasa dengan pustaka template nyata.
Kelemahan dari hal di atas adalah bahwa variabel template harus berupa kata sendiri (mis. Anda tidak dapat melakukannya
"%prefix%foo"
). Ini bisa diperbaiki dengan beberapa modifikasi, atau hanya dengan mengkodekan variabel templat alih-alih dinamis.sumber