bash betiğinin komuttaki geçici değeri


11

Aşağıdaki komut gibi,

if true; then
   IFS=":" read a b c d e f <<< "$test"

Kitap, değer atama komutu ( IFS ":") ana komuttan ( read a b c d e f <<< "$value") önce kullanıldığında , değerinin ana komutta geçici olarak etkili olduğunu söyler . Yani, readkomut sınırlayıcı kullanır :.

Ancak, bu komut gibi,

if true; then
   HOME="hello" echo "$HOME"

Yankı mesajı merhaba değil. Yukarıdaki komutun gerçek anlamı nedir?

Yanıtlar:


5

Bu, değerlendirmenin nasıl çalıştığı sorusuna gelir. Her iki örnek de aynı şekilde çalışır; sorun, kabuğun (bash, burada) değişkenleri nasıl genişlettiği nedeniyle oluşur.

Bu komutu yazdığınızda:

HOME="foo" echo $HOME

$HOMEGenişletilir komut çalıştırılır önce . Bu nedenle, komut için ayarladığınız yeni değere değil, orijinal değerine genişletilir. HOMEDeğişken gerçekten bu ortamda değiştirildi echokomut ancak, yazdırdığınız, çalışan $HOMEebeveynden.

Açıklamak için şunu göz önünde bulundurun:

$ HOME="foo" bash -c 'echo $HOME'
foo
$ echo $HOME
/home/terdon

Yukarıda görebileceğiniz gibi, ilk komut geçici olarak değiştirilen değerini HOME, ikincisi orijinali yazdırır ve değişkenin sadece geçici olarak değiştirildiğini gösterir. Çünkü bash -c ...komutu (tek tırnak içine alınır ' 'yerine çift olanlar (bir) " "), değişken genişletilmediğinde ve yeni bash sürecine olduğu gibi geçirilir. Bu yeni işlem daha sonra genişletir ve ayarlandığı yeni değeri yazdırır. Kullanırsanız bunun olduğunu görebilirsiniz set -x:

$ set -x
$ HOME="hello" echo "$HOME"
+ HOME=hello         
+ echo hello
hello

Yukarıda gördüğünüz gibi, değişken $HOME asla geçilmez echo. Sadece genişletilmiş değerini görür. İle karşılaştırmak:

$ HOME="hello" bash -c 'echo $HOME'
+ HOME=hello
+ bash -c 'echo $HOME'
hello

Burada, tek tırnaklar nedeniyle, değeri değil, değişken yeni işleme geçirilir.


8

Kabuk bir satırı ayrıştırdığında, satırı kelimelere işaretler, kelimelere çeşitli açılımlar (sırayla) uygular, sonra komutu yürütür.

varsaymak test=1:2:3:4:5:6

Bu komuta bakalım: IFS=":" read a b c d e f <<< "$test"

Tokenleştirmeden sonra ve parametre genişletme gerçekleşir:IFS=":" read a b c d e f <<< "1:2:3:4:5:6"

Kabuk, IFS değişkenini read komutu süresince ayarlayacak readve girişine $ IFS nasıl uygulanacağını ve değişken adlarına nasıl değer verileceğini bilir .

Bu komutun benzer bir hikayesi var, ancak farklı bir sonucu var: HOME="hello" echo "$HOME"

Parametre genişletme komut başlamadan önce gerçekleştiği için, kabukta şunlar bulunur:

HOME="hello" echo "/home/username"

Ve sonra, echo komutunun yürütülmesi sırasında, yeni $ HOME değeri hiç kullanılmaz.

Yapmaya çalıştığınız şeyi başarmak için aşağıdakilerden birini seçin:

# Delay expansion of the variable until its new value is set
HOME="hello" eval 'echo "$HOME"'

veya

# Using a subshell, so the altered env variable does not affect the parent.
# The semicolon means that the variable assignment will occur before
# the variable expansion
(HOME="hello"; echo "$HOME")

ama ilki seçmeyin.


İlkini seçmek muhtemelen daha iyidir. En azından önemli ölçüde daha hızlı. Eval cevabı olduğunda, bazen yanlış soruyu soruyorsun. Ancak birisinin bunu bazı nedenlerle yapması gerekiyorsa, cevabı değiştirmek sorunun kendisini daha az yanlış yapmaz. Başka bir çözüm, onu bir işleve sarmak ve kullanmaktır local.
user23013

Çözümden neden evalkaçınılmalıdır?
DarkHeart

Girişi sıkı bir şekilde kontrol etmezseniz, diğer kişilerin programınıza enjekte etmesine izin verdiğiniz kod konusunda çok dikkatli olmalısınız.
glenn jackman

-1

İki kapsam vardır: ortam değişkenleri ve yerel değişkenler. Yerel değişkenler yalnızca bu kabuk oturumu içinde etkinken, ortam değişkenleri her işlem (bkz setenv. getenv) İçin geçerlidir . (Bu bariz bir ayrım değil ...)

Zımni env(örneğin örnekte olduğu gibi) çevreyi değiştirirken echo ..., yerel olanları kullanır - yani envhiçbir etkisi yoktur.

Yerel değişkenleri değiştirmek için şunu kullanın:

( HOME="foo" ; echo "$HOME" )

Burada parantezler bu atamanın kapsamını tanımlar.


1
Bunun değişken kapsamla ilgisi yoktur, sorun değişkenin alt kabuğa geçirilmeden önce genişletilmesidir.
terdon
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.