Referensi variabel dalam skrip shell


10

Dalam skrip shell, jika saya mendefinisikan variabel seperti FOO=25, apakah ada perbedaan antara referensi sebagai $FOO$dan ${FOO}$?


2
Anda tidak boleh menggunakan $pada akhirnya! Ini akan diperlakukan sebagai karakter normal dan bukan sebagai bagian dari nama variabel.
Byte Commander

Jawaban:


16

Dalam kebanyakan situasi baik $vardan ${var}adalah sama. (Perhatikan bahwa Anda tidak boleh menggunakan $di akhir!)

Salah satu contoh di mana Anda perlu kurung kurawal adalah ketika Anda harus meletakkan variabel dalam string yang berkelanjutan.

Contoh:

var=hel
echo ${var}lo

akan menampilkan hello.


11

Untuk menjawab pertanyaan utama Anda, ${foo}disebut "ekspansi parameter" . Tepatnya, $parameter itu sendiri memulai ekspansi parameter, { }sebenarnya opsional sesuai dengan spesifikasi POSIX , tetapi dapat berguna untuk menunjukkan akhir nama variabel:

$ foo="bar"
$ echo $fooBaz   ## fails, no variable named $fooBaz exists

$ echo ${foo}Baz ## works, $foo is expanded and the string Baz is appended
barBaz

Pada dasarnya, $foodan ${foo}identik. Terlepas dari kasus-kasus seperti di atas atau ketika Anda melakukan manipulasi string , mereka sepenuhnya setara.

Namun, Anda sebaiknya tidak menggunakan keduanya. Aturan praktisnya adalah bahwa, dengan sedikit pengecualian, Anda harus selalu menggunakan "$foo"atau "${foo}"dan tidak pernah $fooatau ${foo}. Anda harus selalu mengutip variabel Anda untuk menghindari meminta operator split + glob (lebih lanjut tentang itu nanti). Anda tentu tidak mau $foo$. Final $tidak relevan:

$ foo="bar"
$ echo "$foo$"
bar$

Jadi, sementara variabel yang tidak dikutip kadang-kadang OK:

$ echo $foo
bar

Mereka biasanya tidak dan harus benar-benar dihindari:

$ if [ -n $foo ]; then echo empty; else echo "not empty"; fi ## fails
empty

$ if [ -n "$foo" ]; then echo empty; else echo "not empty"; fi ## works
not empty

Perhatikan bahwa kurung juga tidak membantu di sini:

$ if [ -n ${foo} ]; then echo empty; else echo "not empty"; fi  ## fails
empty

$ if [ -n "${foo}" ]; then echo empty; else echo "not empty"; fi ## works
not empty

Saat Anda menggunakan $fooatau ${foo}, shell akan membagi nilai yang disimpan dalam variabel di spasi putih (ini dapat diubah dengan mengatur IFSvariabel ke sesuatu yang lain) menjadi daftar dan kemudian, setiap elemen daftar diperlakukan sebagai pola gumpalan dan diperluas ke file atau direktori yang cocok. Ini dikenal sebagai operator split + glob . Untuk mengilustrasikannya, pertimbangkan direktori dengan dua file:

$ ls -l
-rw-r--r-- 1 terdon terdon 0 Oct  9 18:16 file1
-rw-r--r-- 1 terdon terdon 0 Oct  9 18:16 file2

Sekarang, mari kita tetapkan variabel ke foo *:

$ foo="foo *"

Apa yang terjadi jika kami mencoba memeriksa apakah ada file dengan nama itu?

$ if [ -e $foo ]; then echo "file exists"; else echo "no such file"; fi
file exists

Variabel dipecah menjadi foodan *dan, karena *wildcard yang cocok dengan string apa pun, shell memberitahu Anda bahwa file bernama foo *exxists. Namun, jika kami mengutipnya dengan benar, ini tidak terjadi:

$ if [ -e "$foo" ]; then echo "file exists"; else echo "no such file"; fi
no such file

Itu adalah contoh sepele untuk menggambarkan hal tersebut. Bayangkan jika saya telah menggunakan rmbukannya echosekalipun.

Jadi, aturan pertama: selalu kutip variabel Anda. Anda dapat menggunakan salah satu "$foo"atau "${foo}"tetapi mengutipnya dengan cara apa pun. Untuk detail lebih lanjut tentang penggunaan variabel dengan aman, lihat posting ini:


Saya tidak ingin mengedit jawaban Anda sebaliknya sangat baik, tetapi seharusnya tidak $ var="foo *"menjadi $ foo="foo *"? Anda tidak menggunakannya di varmana pun.
Joe

@ Jo, oh, astaga! Ya, tentu saja harus, terima kasih sudah menunjukkannya. Jangan ragu untuk memperbaiki kesalahan seperti itu dengan menyarankan suntingan. Hal semacam itu sangat dianjurkan, tepatnya untuk menghindari kesalahan konyol seperti ini.
terdon
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.