Atamalar, komut değiştirme yerine çıkış durumundaki komutlar gibidir?


10

POSIX mermilerinde aşağıdaki örneklere ve bunların çıktılarına bakın:

  1. false;echo $?veya false || echo 1:1
  2. false;foo="bar";echo $?veya foo="bar" && echo 0:0
  3. foo=$(false);echo $?veya foo=$(false) || echo 1:1
  4. foo=$(true);echo $?veya foo=$(true) && echo 0:0

Https://stackoverflow.com/questions/6834487/what-is-the-variable-in-shell-scripting adresindeki en yüksek oyu alan yanıtta belirtildiği gibi :

$? son yürütülen komutun dönüş değerini bulmak için kullanılır.

Bu muhtemelen bu durumda biraz yanıltıcıdır, bu yüzden bu iş parçacığından bir gönderide de belirtilen POSIX tanımını alalım:

? En son boru hattının ondalık çıkış durumuna genişler (bkz. Boru Hatları).

Öyleyse, bir atamanın kendisi sıfır çıkış değerine sahip bir komut (ya da daha doğrusu bir boru hattı parçası) olarak sayılır, ancak atamanın sağ tarafından uygulanmadan önce görünür (örn. Komut ikamesi buradaki örneklerimde çağırır).

Bu davranışın pratik açıdan nasıl mantıklı olduğunu görüyorum, ancak bana göre ödevin kendisi bu sırayla sayılır. Belki benim için neden garip olduğunu daha açık hale getirmek için, ödevin bir işlev olduğunu varsayalım:

ASSIGNMENT( VARIABLE, VALUE )

o foo="bar"zaman olur

ASSIGNMENT( "foo", "bar" )

ve foo=$(false)şöyle bir şey olurdu

ASSIGNMENT( "foo", EXECUTE( "false" ) )

hangi anlamına gelir EXECUTEçalışır birinci ve ancak ondan sonra ASSIGNMENT çalıştırılır ama hala var EXECUTEburada önemli olan durum.

Değerlendirmemde doğru muyum veya bir şeyi yanlış anlıyor / özlüyor muyum? Bu davranışı "tuhaf" olarak görmem için doğru nedenler bunlar mı?


1
Üzgünüm, ama garip bulduğunuzun ne olduğu belli değil.
Kusalananda

1
@Kusalananda Belki de benimle başladığımı kendime sorduğumu söylemenize yardımcı olur: " false;foo="bar";echo $?Son çıkan gerçek komut neden her zaman 0false döndürüyor ?" Temel olarak, çıkış kodları söz konusu olduğunda atamaların özel davranmasıdır. Görevin sağ tarafının bir parçası olarak çalışan bir şey olmadığı için çıkış kodları her zaman 0'dır.
phk

Yanıtlar:


10

Atamalar için çıkış durumu tuhaf . Bir atamanın başarısız olmasının en belirgin yolu, hedef değişkenin işaretlenmiş olmasıdır readonly.

$ err(){ echo error ; return ${1:-1} ; }
$ PS1='$? $ '
0 $ err 42
error
42 $ A=$(err 12)
12 $ if A=$(err 9) ; then echo wrong ; else E=$? ; echo "E=$E ?=$?" ; fi
E=9 ?=0
0 $ readonly A
0 $ if A=$(err 10) ; then echo wrong ; else E=$? ; echo "E=$E ?=$?" ; fi
A: is read only
1 $

İf ifadesinin ne doğru ne de yanlış yollarının alınmadığını, başarısız olan atamanın tüm ifadenin yürütülmesini durdurduğunu unutmayın. POSIX modunda bash ve ksh93 ve zsh, atama başarısız olursa komut dosyasını iptal eder.

Bu konuda POSIX standardını belirtmek için :

Komut adı olmayan, ancak komut değiştirme içeren bir komut, kabuğun gerçekleştirdiği son komut değiştirme işleminin çıkış durumuna sahiptir.

Bu tam olarak kabuk gramerinin bir parçası

 foo=$(err 42)

hangi gelen bir simple_command(simple_command → cmd_prefix → ASSIGNMENT_WORD). Dolayısıyla, bir atama başarılı olursa, komut değişikliği yapılmadığı sürece çıkış durumu sıfır olur, bu durumda çıkış durumu sonuncunun durumudur. Atama başarısız olursa, çıkış durumu sıfır değildir, ancak atama yapamayabilirsiniz.


1
Cevabınıza eklemek için, burada daha yeni bir POSIX standardının belirtildiği farklı bir iş parçacığının cevabı, sonuç temel olarak aynıdır: unix.stackexchange.com/a/270831/117599
phk

4

Diyorsun,

… 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. Ancak 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=

Ayrıca, icarus'un işaret ettiği gibi , değişkenler salt okunur olarak ayarlanabilir. ICARUS örneğinde aşağıdaki varyasyonu düşünün:

$ err() { echo "stdout $*"; echo "stderr $*" >&2; return ${1:-1}; }
$ readonly A
$ Z=$(err 41 zebra) A=$(err 42 antelope) B=$(err 43 badger)
stderr 41 zebra
stderr 42 antelope
bash: A: readonly variable
$ echo $?
1
$ printf "%s = %s\n" Z "$Z" A "$A" B "$B"
Z = stdout 41 zebra
A =
B =
$

Her ne kadar Asalt okunur olsa da, bash komut ikamesini sağında A=- yerine getirir ve sonraA salt okunur olduğu için komutu iptal eder . Bu, ödevin çıkış değerinin ödevin sağ tarafından önce geçerli olduğu yorumuyla çelişir.

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.