Kapan kita perlu kurung kurawal di sekitar variabel shell?

659

Dalam skrip shell, kapan kita gunakan {}saat memperluas variabel?

Sebagai contoh, saya telah melihat yang berikut:

var=10        # Declare variable

echo "${var}" # One use of the variable
echo "$var"   # Another use of the variable

Apakah ada perbedaan yang signifikan, atau hanya gaya? Apakah yang satu lebih disukai daripada yang lain?

Pengguna baru
sumber

Jawaban:

753

Dalam contoh khusus ini, tidak ada bedanya. Namun, {}in ${}berguna jika Anda ingin memperluas variabel foodalam string

"${foo}bar"

karena "$foobar"sebaliknya akan memperluas variabel yang diidentifikasi oleh foobar.

Kurung kurawal juga dibutuhkan tanpa syarat saat:

  • memperluas elemen array, seperti pada ${array[42]}
  • menggunakan operasi ekspansi parameter, seperti pada ${filename%.*}(hapus ekstensi)
  • memperluas parameter posisi di luar 9: "$8 $9 ${10} ${11}"

Melakukan hal ini di mana-mana, alih-alih hanya dalam kasus-kasus yang berpotensi ambigu, dapat dianggap sebagai praktik pemrograman yang baik. Ini untuk konsistensi dan untuk menghindari kejutan seperti $foo_$bar.jpg, di mana tidak jelas secara visual bahwa garis bawah menjadi bagian dari nama variabel.

Fred Foo
sumber
106
{}dikenal sebagai ekspansi brace . ${}dikenal sebagai ekspansi variabel. Mereka melakukan hal yang berbeda. Saya akan mendukung Anda kecuali sedikit ekspansi.
Spencer Rathbun
5
@NewUser " Jadi selain array tidak benar-benar diperlukan " Tidak begitu, kawat gigi diperlukan untuk PARAMETER EXPANSION , konstruksi yang sangat berguna dalam skrip. Saya telah melihat banyak skrip sed dan awk yang dapat diganti dengan sedikit ekspansi parameter.
SiegeX
10
@caffinatedmonkey $()digunakan untuk mengeksekusi perintah, sehingga md5sum=$(md5sum foo.bin)akan menyimpan output md5sum foo.bindalam variabel md5sum, yang sekarang dapat diakses menggunakan ${md5sum}. +1, dan masih banyak lagi dalam semangat untuk OP karena menyebutkan bahwa itu praktik yang baik untuk menjadi eksplisit!
L0j1k
11
@ L0j1k Berbicara tentang kesaksian, saya merasa penting untuk menyebutkan bahwa $()mengeksekusi perintahnya dari sebuah subkulit .
Adrian Günter
2
@karatedog ${1:-20}adalah bentuk ekspansi parameter. Di sini tidak jelas karena ini terutama menggunakan digit dan operator aritmatika yang menipu kita dalam berpikir ada aritmatika yang terlibat, tetapi sebenarnya mengacu pada parameter posisi $1, yang jika tidak didefinisikan akan diganti oleh nilai default 20(sintaksnya adalah ${variable:-default_value}).
Aaron
126

Variabel dideklarasikan dan ditugaskan tanpa $dan tanpa {}. Anda harus menggunakan

var=10

untuk menetapkan. Untuk membaca dari variabel (dengan kata lain, 'perluas' variabel), Anda harus menggunakan $.

$var      # use the variable
${var}    # same as above
${var}bar # expand var, and append "bar" too
$varbar   # same as ${varbar}, i.e expand a variable called varbar, if it exists.

Ini kadang membuat saya bingung - dalam bahasa lain kami merujuk variabel dengan cara yang sama, terlepas dari apakah itu di sebelah kiri atau kanan tugas. Tetapi shell-scripting berbeda, $var=10tidak melakukan apa yang Anda pikirkan!

Aaron McDaid
sumber
34

Anda gunakan {}untuk pengelompokan. Kawat gigi diperlukan untuk elemen array dereference. Contoh:

dir=(*)           # store the contents of the directory into an array
echo "${dir[0]}"  # get the first entry.
echo "$dir[0]"    # incorrect
glenn jackman
sumber
Saya tidak bisa mengerti baris pertama dir=(*). Sejauh yang saya tahu, diradalah perintah bawaan untuk membuat daftar isi direktori (setara dengan ls -C -b). Bisakah Anda jelaskan?
Jarvis
1
Dalam pemrograman shell, perintah dan argumen harus dipisahkan satu sama lain oleh spasi. Di sini, Anda melihat tanda sama dengan tanpa spasi, artinya ini adalah penugasan variabel. diradalah nama variabel, dan tanda kurung digunakan untuk mengumpulkan ekspansi nama file *ke dalam array.
glenn jackman
27

Anda juga dapat melakukan beberapa manipulasi teks di dalam kurung:

STRING="./folder/subfolder/file.txt"
echo ${STRING} ${STRING%/*/*}

Hasil:

./folder/subfolder/file.txt ./folder

atau

STRING="This is a string"
echo ${STRING// /_}

Hasil:

This_is_a_string

Anda benar dalam "variabel biasa" tidak diperlukan ... Tetapi lebih bermanfaat untuk debugging dan membaca skrip.

SierraX
sumber
11

Akhir nama variabel biasanya ditandai oleh spasi atau baris baru. Tetapi bagaimana jika kita tidak menginginkan spasi atau baris baru setelah mencetak nilai variabel? Kurung kurawal memberi tahu penerjemah shell di mana akhir nama variabel.

Contoh Klasik 1) - variabel shell tanpa tertinggal spasi

TIME=10

# WRONG: no such variable called 'TIMEsecs'
echo "Time taken = $TIMEsecs"

# What we want is $TIME followed by "secs" with no whitespace between the two.
echo "Time taken = ${TIME}secs"

Contoh 2) Java classpath dengan toples berversi

# WRONG - no such variable LATESTVERSION_src
CLASSPATH=hibernate-$LATESTVERSION_src.zip:hibernate_$LATEST_VERSION.jar

# RIGHT
CLASSPATH=hibernate-${LATESTVERSION}_src.zip:hibernate_$LATEST_VERSION.jar

(Jawaban Fred sudah menyatakan ini tetapi contohnya agak terlalu abstrak)

Sridhar Sarnobat
sumber
5

Kurung kurawal selalu dibutuhkan untuk mengakses elemen larik dan melakukan ekspansi penjepit.

Adalah baik untuk tidak terlalu berhati-hati dan menggunakan {}ekspansi variabel shell bahkan ketika tidak ada ruang untuk ambiguitas.

Sebagai contoh:

dir=log
prog=foo
path=/var/${dir}/${prog}      # excessive use of {}, not needed since / can't be a part of a shell variable name
logfile=${path}/${prog}.log   # same as above, . can't be a part of a shell variable name
path_copy=${path}             # {} is totally unnecessary
archive=${logfile}_arch       # {} is needed since _ can be a part of shell variable name

Jadi, lebih baik menulis tiga baris sebagai:

path=/var/$dir/$prog
logfile=$path/$prog.log
path_copy=$path

yang pasti lebih mudah dibaca.

Karena nama variabel tidak dapat dimulai dengan digit, shell tidak perlu di {}sekitar variabel bernomor (seperti $1, $2dll.) Kecuali ekspansi tersebut diikuti oleh digit. Itu terlalu halus dan tidak digunakan secara eksplisit {}dalam konteks seperti itu:

set app      # set $1 to app
fruit=$1le   # sets fruit to apple, but confusing
fruit=${1}le # sets fruit to apple, makes the intention clear

Lihat:

codeforester
sumber
1
It's good to be not over-cautious: Saya ingin tahu apa yang dipikirkan kebanyakan orang. Gunakan kurung kurawal sepanjang waktu sehingga Anda tidak melupakannya saat dibutuhkan, atau menggunakannya hanya jika diperlukan, untuk meningkatkan keterbacaan.
Roger Dahl
1
Saya pikir itu adalah kurangnya kesadaran yang menyebabkan pemrogram menggunakan ikal bahkan ketika mereka tidak diperlukan. Ketidaktahuan ini mirip dengan kesalahan umum lainnya yaitu tidak menggunakan tanda kutip ganda untuk mencegah pemisahan kata atau penggumpalan yang tidak disengaja. Pada dasarnya, kenyataannya adalah bahwa programmer tidak serius tentang skrip shell sebanyak bahasa skrip lain seperti Python dan Ruby.
codeforester
1
Benar bahwa. Kencing binatang peliharaan saya adalah bahwa semua orang tampaknya berpikir bahwa semua variabel harus semuanya huruf besar dalam skrip shell :)
Roger Dahl
2

Mengikuti saran SierraX dan Peter tentang manipulasi teks, kurung keriting {}digunakan untuk meneruskan variabel ke perintah, misalnya:

Katakanlah Anda memiliki file sposi.txt yang berisi baris pertama novel terkenal Italia:

> sposi="somewhere/myfolder/sposi.txt"
> cat $sposi

Ouput: quel ramo del lago di como che volge a mezzogiorno

Sekarang buat dua variabel:

# Search the 2nd word found in the file that "sposi" variable points to
> word=$(cat $sposi | cut -d " " -f 2)

# This variable will replace the word
> new_word="filone"

Sekarang gantikan konten variabel kata dengan yang ada di new_word , di dalam file sposi.txt

> sed -i "s/${word}/${new_word}/g" $sposi
> cat $sposi

Ouput: quel filone del lago di como che volge a mezzogiorno

Kata "ramo" telah diganti.

Fabio Natalini
sumber
1
Ini berfungsi dengan baik tanpa kurung kurawal di sekitar variabel.
Armali
Anda mungkin ingin memperbaiki weel-known novelsedikit. Namun demikian, tervotasikan.
gsl