Tugas seperti perintah dengan status keluar kecuali ketika ada substitusi perintah?


10

Lihat contoh berikut dan hasilnya dalam cangkang POSIX:

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

Seperti yang disebutkan oleh jawaban pilihan tertinggi di /programming/6834487/what-is-the-variable-in-shell-scripting :

$? digunakan untuk menemukan nilai kembali dari perintah yang dieksekusi terakhir.

Ini mungkin agak menyesatkan dalam kasus ini, jadi mari kita dapatkan definisi POSIX yang juga dikutip dalam posting dari utas itu:

? Perluas ke status keluar desimal dari pipa terbaru (lihat Pipa).

Jadi tampak seolah-olah penugasan itu sendiri dihitung sebagai perintah (atau lebih tepatnya bagian pipa) dengan nilai keluar nol tetapi yang berlaku sebelum sisi kanan penugasan (misalnya substitusi perintah memanggil dalam contoh saya di sini).

Saya melihat bagaimana perilaku ini masuk akal dari sudut pandang praktis tetapi tampaknya agak tidak biasa bagi saya bahwa tugas itu sendiri akan dihitung dalam urutan itu. Mungkin untuk memperjelas mengapa itu aneh bagi saya, mari kita asumsikan tugasnya adalah fungsi:

ASSIGNMENT( VARIABLE, VALUE )

maka foo="bar"akan menjadi

ASSIGNMENT( "foo", "bar" )

dan foo=$(false)akan menjadi sesuatu seperti

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

yang berarti EXECUTEberjalan pertama dan hanya setelah ASSIGNMENT itu dijalankan tetapi masih EXECUTEstatus yang penting di sini.

Apakah saya benar dalam penilaian saya atau saya salah paham / melewatkan sesuatu? Apakah itu alasan yang tepat bagi saya untuk melihat perilaku ini sebagai "aneh"?


1
Maaf, tetapi tidak jelas bagi saya apa yang Anda temukan aneh.
Kusalananda

1
@ Kusalananda Mungkin ada baiknya memberitahu Anda bahwa itu dimulai dengan saya bertanya pada diri sendiri: "Mengapa false;foo="bar";echo $?selalu kembali 0 ketika perintah sebenarnya terakhir yang dijalankan adalah false? Ini pada dasarnya bahwa tugas berperilaku khusus ketika datang untuk keluar dari kode. Kode keluar mereka selalu 0, kecuali ketika itu bukan karena sesuatu yang berlari sebagai bagian dari sisi kanan penugasan.
phk

Jawaban:


10

Status keluar untuk tugas aneh . Cara yang paling jelas untuk sebuah tugas gagal adalah jika variabel target ditandai 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 $

Perhatikan bahwa baik jalur benar atau salah dari pernyataan if diambil, penugasan yang gagal menghentikan eksekusi seluruh pernyataan. bash dalam mode POSIX dan ksh93 dan zsh semua akan membatalkan skrip jika tugas gagal.

Mengutip standar POSIX pada ini :

Perintah tanpa nama perintah, tetapi perintah yang menyertakan substitusi perintah, memiliki status keluar dari substitusi perintah terakhir yang dijalankan oleh shell.

Ini persis bagian dari tata bahasa shell yang terlibat

 foo=$(err 42)

yang berasal dari simple_command(simple_command → cmd_prefix → ASSIGNMENT_WORD). Jadi jika tugas berhasil maka status keluar adalah nol kecuali penggantian substitusi terlibat, dalam hal ini status keluar adalah status yang terakhir. Jika tugas gagal maka status keluar tidak nol, tetapi Anda mungkin tidak dapat menangkapnya.


1
Untuk menambah jawaban Anda, berikut ini adalah jawaban dari utas yang berbeda di mana dikutip oleh POSIX standar yang lebih baru, kesimpulannya pada dasarnya sama: unix.stackexchange.com/a/270831/117599
phk

4

Kamu bilang,

... tampaknya seolah-olah suatu tugas itu sendiri dihitung sebagai perintah ... dengan nilai keluar nol, tetapi yang berlaku sebelum sisi kanan tugas (misalnya, panggilan substitusi perintah ...)

Itu bukan cara yang mengerikan untuk melihatnya. Tapi ini sedikit penyederhanaan. Status pengembalian keseluruhan dari

A = $ ( cmd 1 ) B = $ ( cmd 2 ) C = $ ( cmd 3 ) D = $ ( cmd 4 ) E = mc 2
adalah status keluar dari . The tugas yang terjadi setelah tugas tidak menetapkan status keluar keseluruhan untuk 0.cmd4E=D=

Juga, seperti yang ditunjukkan icarus , variabel dapat diatur sebagai hanya baca. Pertimbangkan variasi berikut pada contoh icarus:

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

Meskipun Ahanya bisa dibaca, bash menjalankan substitusi perintah ke kanan A=- dan kemudian membatalkan perintah karena Ahanya bisa dibaca. Ini lebih jauh bertentangan dengan interpretasi Anda bahwa nilai keluar dari tugas berlaku sebelum sisi kanan tugas.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.