Değişken atamanın dönüş durumu nasıl belirlenir?


10

Ben böyle scriptlerde yapılar gördüm:

if somevar="$(somecommand 2>/dev/null)"; then
...
fi

Bu bir yerde belgelendi mi? Bir değişkenin dönüş durumu nasıl belirlenir ve komut ikamesi ile nasıl ilişkilidir? (Örneğin, aynı sonucu alır if echo "$(somecommand 2>/dev/null)"; thenmıyım?)

Yanıtlar:


13

Bölüm 2.9.1 Açık Grup Tabanı Spesifikasyonlarının Basit Komutları bölümünde (POSIX için) belgelenmiştir . Orada bir metin duvarı var; Dikkatinizi son paragrafa yönlendiriyorum:

Bir komut adı varsa, yürütme, Komut Arama ve Yürütme bölümünde açıklandığı gibi devam edecektir . Komut adı yoksa, ancak komut bir komut değiştirme içeriyorsa, komut, gerçekleştirilen son komut değiştirme işleminin çıkış durumu ile tamamlanır. Aksi takdirde, komut sıfır çıkış durumuyla tamamlanmalıdır.

Yani mesela,

   Command                                         Exit Status
$ FOO=BAR                                   0 (but see also the note from icarus, below)
$ FOO=$(bar)                                Exit status from "bar"
$ FOO=$(bar) baz                            Exit status from "baz"
$ foo $(bar)                                Exit status from "foo"

Bash de böyle çalışır. Ancak sondaki “o kadar basit değil” bölümüne de bakın.

phk , sorusunda Ödevler komut değiştirme dışında bir çıkış durumu olan komutlar gibidir? , öneriyor

… Bir ödevin kendisi sıfır çıkış değeri olan bir komut olarak sayılır, ancak ödevin sağ tarafından uygulanmadan önce görünür (örn. Bir komut değiştirme çağrısı…)

Bu ona bakmak için korkunç bir yol değil. Basit bir komutun geri durumunu belirlemek için bir ham düzeni (bir içermeyen ;, &, |, &&ya da ||) aşağıdaki gibidir:

  • Sona veya bir komut kelimesine (genellikle bir program adı) ulaşıncaya kadar satırı soldan sağa tarayın.
  • Değişken ataması görürseniz, satırın dönüş durumu 0 olabilir.
  • Bir komut ikamesi görürseniz - yani, $(…)komuttan çıkış durumunu alın.
  • Gerçek bir komuta ulaşırsanız (komut yerine değil), bu komuttan çıkış durumunu alın.
  • Satırın dönüş durumu, karşılaştığınız son sayıdır.
    Komuta bağımsız değişkenler olarak komut ikameleri , örneğin foo $(bar)sayılmaz; çıkış durumunu alırsınız foo. Phk gösterimini yorumlamak için , buradaki davranış

    temporary_variable  = EXECUTE( "bar" )
    overall_exit_status = EXECUTE( "foo", temporary_variable )

Ama bu hafif bir aşırı basitleştirme. Genel iade durumu

A = $ ( cmd 1 ) B = $ ( cmd 2 ) C = $ ( cmd 3 ) D = $ ( cmd 4 ) E = mc 2
, çıkış durumudur . Sonra gerçekleşir atama atama 0'a genel çıkış durumu belirlemez.cmd4E=D=

Icarus , içinde PHK sorusuna verdiği cevap , önemli bir noktayı gündeme getiriyor: değişkenler salt okunur olarak ayarlanabilir. POSIX standardının 2.9.1 Bölümündeki üçüncü-son paragraf diyor ki:

Değişken atamalarından herhangi biri, geçerli kabuk ortamında salt okunur özniteliğin ayarlandığı bir değişkene bir değer atamaya çalışırsa (atamanın bu ortamda yapılıp yapılmadığına bakılmaksızın), değişken atama hatası oluşacaktır. Bu hataların sonuçları için Kabuk Hatalarının Sonuçları bölümüne bakın .

yani diyorsan

readonly A
C=Garfield A=Felix T=Tigger

Dönüş durumu 1'dir önemi olmaksızın eğer dizeleri Garfield, Felixve / veya Tigger komut ikamesi (s) ile değiştirilir - ama aşağıdaki notlara bakın.

Bölüm 2.8.1 Kabuk Hatalarının Sonuçları başka bir metin grubuna ve bir tabloya sahiptir ve

Etkileşimli bir kabuğun çıkmaması gereken tabloda gösterilen tüm durumlarda, kabuk, hatanın oluştuğu komutun başka bir işlemini gerçekleştirmemelidir.

Bazı detaylar mantıklı; bazıları şunları yapmaz:

  • A=Atama bazen iptal o son cümle belirtmek için göründüğü gibi, komut satırı. Yukarıdaki örnekte, Cayarlanmıştır Garfield, ancak Tayarlanmamıştır (ve elbette ikisi de ayarlanmamıştır  A).
  • Benzer şekilde, yürütür ama değil . Ama, (4.1.x ve 4.3.X dahil) Bash benim sürümlerinde, bu yok yürütmek . (Bu arada, phk'ın ödevin çıkış değerinin ödevin sağ tarafından önce geçerli olduğu yorumunu da etkiler.)C=$(cmd1) A=$(cmd2) T=$(cmd3)cmd1cmd3
    cmd2

Ama işte bir sürpriz:

Bash versiyonlarımda,

salt okunur A
C = bir şey A = bir şey T = bir şey  cmd 0

yok yürütmek. Özellikle,cmd0

C = $ ( cmd 1 ) A = $ ( cmd 2 ) T = $ ( cmd 3 )    cmd 0
yürütür ve ancak . (Komut olmadığında bunun davranışının tersi olduğuna dikkat edin.) Ve, (yanı sıra ) ortamında da ayarlar . Bunun bash'da bir hata olup olmadığını merak ediyorum.cmd1cmd3cmd2TCcmd0


O kadar basit değil:

Bu cevabın ilk paragrafı “basit komutlar” ile ilgilidir.  Spesifikasyon diyor ki,

"Basit komut", herhangi bir sırada isteğe bağlı olarak değişken atamaları ve yeniden yönlendirmelerden oluşan bir dizidir ve isteğe bağlı olarak bir denetim operatörü tarafından sonlandırılan kelimeler ve yeniden yönlendirmeler gelir.

Bunlar benim ilk örnek bloğumdakiler gibi ifadelerdir:

$ FOO=BAR
$ FOO=$(bar)
$ FOO=$(bar) baz
$ foo $(bar)

bunların ilk üçü değişken atamaları içerir ve son üçü komut ikamelerini içerir.

Ancak bazı değişken atamalar o kadar basit değildir.  bash (1) diyor ki,

Atama ifadeleri de argüman olarak görünebilir alias, declare, typeset, export, readonly, ve localkomutları (yerleşik beyan komutları).

İçin export, POSIX şartname diyor

ÇIKIŞ DURUMU

    0
      Tüm ad işlenenleri başarıyla dışa aktarıldı.
    > 0
      En az bir ad dışa aktarılamadı veya -pseçenek belirtildi ve bir hata oluştu.

POSIX desteklemiyor local, ancak bash (1) diyor ki,

localBir işlev içinde değilken kullanmak bir hatadır . localBir işlevin dışında kullanılmadığı, geçersiz bir ad girilmediği veya ad salt okunur bir değişken olmadığı sürece dönüş durumu 0'dır .

Satır aralarını okurken, bildirim komutlarının

export FOO=$(bar)

ve

local FOO=$(bar)

daha çok benziyor

foo $(bar)

onlar dan çıkış durumu görmezden sürece bar ve size ana komuta dayalı bir çıkış durumunu vermek ( export, localveya foo). Yani tuhaflığımız var

   Command                                           Exit Status
$ FOO=$(bar)                                    Exit status from "bar"
                                                  (unless FOO is readonly)
$ export FOO=$(bar)                             0 (unless FOO is readonly,
                                                  or other error from “export”)
$ local FOO=$(bar)                              0 (unless FOO is readonly,
                                                  statement is not in a function,
                                                  or other error from “local”)

hangi ile gösterebiliriz

$ export FRIDAY=$(date -d tomorrow)
$ echo "FRIDAY   = $FRIDAY, status = $?"
FRIDAY   = Fri, May 04, 2018  8:58:30 PM, status = 0
$ export SATURDAY=$(date -d "day after tomorrow")
date: invalid date ‘day after tomorrow’
$ echo "SATURDAY = $SATURDAY, status = $?"
SATURDAY = , status = 0

ve

myfunc() {
    local x=$(echo "Foo"; true);  echo "x = $x -> $?"
    local y=$(echo "Bar"; false); echo "y = $y -> $?"
    echo -n "BUT! "
    local z; z=$(echo "Baz"; false); echo "z = $z -> $?"
}

$ myfunc
x = Foo -> 0
y = Bar -> 0
BUT! z = Baz -> 1

Neyse ki ShellCheck hatayı yakalar ve SC2155'i yükseltir ;

export foo="$(mycmd)"

olarak değiştirilmeli

foo=$(mycmd)
export foo

ve

local foo="$(mycmd)"

olarak değiştirilmeli

local foo
foo=$(mycmd)

1
Harika teşekkür ederim! Bonus puanlar için, bunun nasıl bir localbağ olduğunu biliyor musunuz ? Örneğin local foo=$(bar)?
Wildcard

1
İkinci örnek için (sadece FOO=$(bar)) teorik olarak hem çıkış durumunun hem de atamanın bir rol oynayabileceğini belirtmek gerekir
phk

1
@Wildcard: Beğendiğine sevindim. Tekrar güncelledim; okuduğunuz sürümün büyük bir kısmı yanlıştı. Burada olduğunuz sürece ne düşünüyorsunuz? Bu bash bir hata mıdır , salt okunur olsa bile A=foo cmdçalışır mı? cmdA
G-Man, '

1
@phk: (1) İlginç bir teori, ama bunun mantıklı olduğundan emin değilim. “Sürpriz” başlığımdan hemen önce örneğe bir göz atın. Eğer Asalt okunur, komut C=value₁ A=value₂ T=value₃setleri Cancak T(ve tabii ki Aayarlı değil) - kabuk yok sayarak komut satırı işleme sonlandırılmış T=value₃, çünkü A=value₂bir hatadır. (2) Yığın Taşması sorusuna bağlantı için teşekkürler - Ben bunun üzerine yorum geldim.
G-Man

1
@Wildcard "Bonus puanlar için, bunun yerelle nasıl bağlandığını biliyor musunuz?". Evet ... local=$(false)çıkış değeri vardır 0çünkü (erkek sayfasından): It is an error to use local when not within a function. The return status is 0 unless local is used outside a function, an invalid name is supplied, or name is a readonly variable.. Bu, onu bu şekilde tasarlayan dahi için dünya üzerinde yeterli trollface değildir.
David Tonhofer

2

Bash ( LESS=+/'^SIMPLE COMMAND EXPANSION' bash) içinde belgelenmiştir :

Genişletmeden sonra bir komut adı kalırsa .... Aksi takdirde komut çıkar. ... Komut ikamesi yoksa, komut sıfır durumundan çıkar.

Başka bir deyişle (kelimelerim):

Genişletmeden sonra komut adı kalmadıysa ve komut yerine başka bir işlem yapılmadıysa, komut satırı sıfır durumundan çıkar.

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.