Kabuk değişkenleri etrafında ne zaman kıvırcık parantezlere ihtiyacımız var?


658

Kabuk komut dosyalarında ne zaman kullanırız {} değişkenleri genişletirken ne zaman ?

Örneğin, aşağıdakileri gördüm:

var=10        # Declare variable

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

Önemli bir fark var mı, yoksa sadece stil mi? Biri diğerine tercih edilir mi?

Yanıtlar:


751

Bu özel örnekte, hiçbir fark yaratmaz. Ancak, dizede değişkeni genişletmek istiyorsanız , {}in ${}yararlıdırfoo

"${foo}bar"

çünkü "$foobar"bunun yerinefoobar .

Kıvırcık ayraçlar ayrıca aşağıdaki durumlarda koşulsuz olarak gereklidir:

  • dizi öğelerini genişletme, ${array[42]}
  • parametre genişletme işlemlerini ${filename%.*}( olduğu gibi, uzantıyı kaldırma) kullanma
  • konum parametrelerini 9'un ötesine genişletme: "$8 $9 ${10} ${11}"

Bunun yerine sadece anlama gelebilecek vakalarda arasında, her yerde bu yaparak, olabilir uygulama programlama düşünülebilir. Bu hem tutarlılık hem $foo_$bar.jpgde alt çizginin değişken adının bir parçası haline geldiği görsel olarak açık olmadığı gibi sürprizlerden kaçınmak içindir .


106
{}destek genişletmesi olarak bilinir . ${}değişken genleşme olarak bilinir. Farklı şeyler yaparlar. Genişletme biti dışında sizi oylarım.
Spencer Rathbun

5
@YeniKullanıcı " Diziler dışında gerçekten gerekli değildir " Bu nedenle, parantezler, komut dosyalamasında çok kullanışlı bir yapı olan PARAMETER GENLEŞME için gereklidir . Ben biraz parametre genişletme ile değiştirilebilir birçok sed ve awk komut dosyaları gördüm.
SiegeX

10
@caffinatedmonkey $()öyle ki, bir komut çalıştırmak için kullanılır md5sum=$(md5sum foo.bin)çıktısını kaydedecek md5sum foo.bindeğişkeninde md5sumşimdi erişilebilir kullanarak ${md5sum}. Ayrıca, +1 ve daha pek çok şey OP'ye açıkça açık olmanın iyi bir uygulama olduğunu belirttiği için!
L0j1k

11
@ L0j1k Açıklıktan bahsetmişken $(), komutunu bir alt kabuktan yürüttüğünü belirtmenin önemli olduğunu düşünüyorum .
Adrian Günter

2
@karatedog ${1:-20}bir parametre genişletme şeklidir. Burada açık değildir, çünkü esasen aritmetik olduğunu düşünmek için bizi kandıracak basamaklar ve aritmetik işleçler kullanır, ancak aslında $1tanımlanmamışsa varsayılan bir değerle değiştirilecek olan konumsal parametreyi ifade eder 20(sözdizimi ${variable:-default_value}).
Aaron

126

Değişkenler ilan ve olmadan atanır $ve olmadan {}. Kullanmak zorundasın

var=10

atamak. Değişkenden okumak için (başka bir deyişle, değişkeni 'genişlet'), kullanmanız gerekir $.

$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.

Bu bazen beni şaşırttı - diğer dillerde, bir ödevin solunda veya sağında olsun, değişkeni aynı şekilde ifade ediyoruz. Ancak kabuk komut dosyası oluşturma farklıdır, $var=10düşündüğünü yapmaz!


34

{}Gruplama için kullanırsınız . Parantez, dizi öğelerinin referanslarının kaldırılması için gereklidir. Misal:

dir=(*)           # store the contents of the directory into an array
echo "${dir[0]}"  # get the first entry.
echo "$dir[0]"    # incorrect

İlk satırı anlayamadım dir=(*). Bildiğim kadarıyla, dirdizin içeriğini (eşdeğer ls -C -b) listelemek için yerleşik bir komuttur . Lütfen açıklar mısın?
Jarvis

1
Kabuk programlamada, komutlar ve argümanlar boşlukla birbirinden ayrılmalıdır. Burada, boşluk olmadan eşittir işaretini görürsünüz, yani bu değişken bir atamadır. dirdeğişkenin adıdır ve parantezler dosya adı genişletmesini *bir diziye toplamak için kullanılır .
glenn jackman

27

Ayrıca parantez içinde bazı metin manipülasyonları yapabilirsiniz:

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

Sonuç:

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

veya

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

Sonuç:

This_is_a_string

Haklısın "düzenli değişkenler" gerekli değil ... Ama hata ayıklama ve bir komut dosyası okumak için daha yararlıdır.


11

Değişken adının sonu genellikle boşluk veya satırsonu ile belirtilir. Ancak, değişken değerini yazdırdıktan sonra boşluk veya satır sonu istemezsek ne olur? Kıvırcık parantezler kabuk yorumlayıcısına değişken adının sonunun nerede olduğunu söyler.

Klasik Örnek 1) - boşluk içermeyen kabuk değişkeni

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"

Örnek 2) Sürümlü kavanozlara sahip Java sınıfyolu

# 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

(Fred'in cevabı zaten bunu söylüyor ama örneği biraz fazla soyut)


5

Dizi elemanlarına erişmek ve küme ayracı genişlemesini gerçekleştirmek için her zaman kıvırcık parantezlere ihtiyaç vardır.

Aşırı ihtiyatlı olmamak ve {}belirsizlik için bir kapsam olmasa bile kabuk değişkeni genişlemesi için kullanmak iyidir .

Örneğin:

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

Bu nedenle, üç satırı şu şekilde yazmak daha iyidir:

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

ki bu kesinlikle daha okunabilir.

Değişken adı bir rakam ile başlayamaz için, kabuk gerek yoktur {}yaklaşık sayılı değişkenleri (gibi $1, $2bu genişleme bir rakam olduğu sürece vb.) Bu çok ince ve bu {}tür bağlamlarda açıkça kullanılmasını sağlıyor :

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

Görmek:


1
It's good to be not over-cautious: Çoğu insanın ne düşündüğünü merak ediyorum. Her zaman kıvırcık parantez kullanın, böylece gerektiğinde onları unutma veya okunabilirliği artırmak için sadece gerektiğinde kullanın.
Roger Dahl

1
Programcılara ihtiyaç duyulmadıklarında bile bukleler kullanmalarına yol açan farkındalık eksikliği olduğunu düşünüyorum. Bu cehalet, yanlışlıkla kelime bölünmesini veya yuvarlanmasını önlemek için çift tırnak kullanmamanın yaygın olarak görülen diğer yanılgısına benzer. Bunun temelinde, programcıların Python ve Ruby gibi diğer komut dosyası dilleri kadar kabuk komut dosyası yazma konusunda da ciddi olmamalarıdır.
codeforester

1
Bu doğru. Benim evcil hayvan peeve herkes kabuk değişkenleri tüm değişkenlerin tüm kapaklar olması gerektiğini düşünüyor gibi görünüyor :)
Roger Dahl

2

SierraX ve Peter'ın metin manipülasyonu hakkındaki önerilerini takiben {}, örneğin bir komuta değişken göndermek için süslü parantez kullanılır:

İyi bilinen bir İtalyan romanının ilk satırını içeren bir sposi.txt dosyanız olduğunu varsayalım :

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

Çıkışı: quel ramo del lago di como che volge a mezzogiorno

Şimdi iki değişken oluşturun:

# 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"

Şimdi yerine kelimesinin biriyle değişken içerik new_word sposi.txt dosyası içinde,

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

Çıkışı: quel filone del lago di como che volge a mezzogiorno

"Ramo" kelimesi değiştirildi.


1
Bu, değişkenlerin etrafında kıvırcık parantez olmadan da işe yarar.
Armali

Biti düzeltmek isteyebilirsiniz weel-known novel. Yine de oy kullandı.
gsl
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.