Menetapkan kode keluar ke variabel lokal shell

42
#!/bin/bash
function0()
{
 local t1=$(exit 1)
 echo $t1
}

function0

echomencetak nilai kosong. Saya mengharapkan:

1

Mengapa t1variabel tidak mendapatkan nilai pengembalian perintah keluar - 1?

Gilles 'SANGAT berhenti menjadi jahat'
sumber

Jawaban:

58

local t1=$(exit 1) memberitahu shell untuk:

  • dijalankan exit 1dalam subkulit;
  • menyimpan outputnya (seperti pada, teks yang di output ke output standar) dalam variabel t1, lokal ke fungsi.

Dengan demikian normal yang t1akhirnya menjadi kosong.

( $()dikenal sebagai substitusi perintah .)

Kode keluar selalu ditetapkan $?, sehingga Anda dapat melakukannya

function0()
{
  (exit 1)
  echo "$?"
}

untuk mendapatkan efek yang Anda cari. Anda tentu saja dapat menetapkan $?ke variabel lain:

function0()
{
  (exit 1)
  local t1=$?
  echo "$t1"
}
Stephen Kitt
sumber
1
Anda tahu, Anda selalu bisa memasukkan kembali ke dalam pipa juga. `$ (trap 'printf" :: ERRNO: $? "' 0; # sekarang lakukan apa saja - perangkap itu akan memastikan string terakhir yang ditulis adalah pengembalian terakhir untuk keseluruhan konteks substitusi.
mikeserv
1
@ mikeserv apakah Anda melewatkan backtick? $(trap 'printf "::ERRNO:$?"' 0; # now do whatever however
Doktor J
12

Kode keluar disimpan dalam $? variabel. Menggunakan Substitusi Perintah hanya menangkap output, Anda harus menggunakan (...) untuk membuat subkulit :

#!/bin/bash

func() {
  (exit 1)
  local t1=$?
  printf '%d\n' "$t1"
}

func
cuonglm
sumber
tujuan dari penugasan t1=$?adalah untuk menggunakannya, bukan? dan tidak akan $?musnah oleh penugasan op? Saya kira saya bertanya apakah tidak seharusnyaprintf '%d\n' "${t1}"
Dani_l
@Dani_l: Terima kasih, itu salah ketik. Diperbarui.
cuonglm
Perhatikan bahwa Substitusi Perintah hanya menangkap standar keluar kecuali diarahkan berbeda.
phyatt
7

Dalam bashkarya ini:

loc(){  local   "x=$(exit "$1"):$?"
        printf  '$%s:\t%d\n' \
                 x "${x##*:}" \? "$?"
}

Itu ada hubungannya dengan urutan evaluasi perintah dan penugasan variabel. localmemiliki nilai pengembalian semua miliknya sendiri - dan itu adalah perintah yang sedang dijalankan, bukan pengganti perintah. Alasan hal-hal seperti ...

x=$(exit 1); echo "$?"

... dapat mengembalikan 1 adalah karena tidak pernah ada pengembalian dalam perintah itu kecuali untuk menjalankan subshell untuk memberikan $xnilai - jadi $?tidak mendapatkan musnah seperti halnya dalam hampir setiap kasus lain di mana penggantian perintah digunakan.

Pokoknya, dengan localitu tidak mendapatkan musnah - tetapi jika Anda menangkapnya pada waktu yang tepat - yang sementara ekspansi masih sedang dievaluasi dan sebelum local 's rutinitas memiliki kesempatan untuk mengkritik itu - Anda masih dapat menetapkan.

unset x; loc 130; echo "${x-\$x is unset}"

... mencetak ...

$x: 130
$?: 0
$x is unset

Anda harus tahu bahwa di banyak shell Anda tidak dapat mengandalkan $?sedang mengatur evaluasi tengah dengan cara itu. Bahkan, itu mungkin karena cangkang tersebut tidak repot mengevaluasi ulang pada setiap saat yang mungkin bashterjadi - yang saya berpendapat mungkin perilaku yang lebih baik daripada bash's. Apakah Anda benar-benar ingin penerjemah Anda mengevaluasi nilai-nilai berulang yang kemungkinan besar akan ditimpa sebelum Anda sempat menggunakannya?

Bagaimanapun, itulah bagaimana Anda bisa melakukan itu.

mikeserv
sumber
-1

Tergantung mengapa Anda mencoba untuk hanya mendapatkan kode keluar Anda juga bisa menjalankan if some-command; then echo "Success $?"; else echo "Failure $?"; fiyang tidak melakukan apa pun dengan output dari perintah, itu hanya mengevaluasi kode keluar dari perintah yang dijalankan. Anda dapat menambahkan or( or$ ( around the command and you'll still get the same results. A better example might bejika grep -q 'somestring' somefile; kemudian echo "Ditemukan kode keluar somestring adalah $?"; Lain "Tidak menemukan kode keluar somestring adalah $?"; Fi`.

Anda juga dapat menguji kode pengembalian suatu fungsi yang bisa berupa return 3kode pengembalian eksplisit atau tersirat yang merupakan hasil dari perintah terakhir, dalam hal ini Anda harus berhati-hati bahwa Anda tidak memiliki echokode di akhir fungsi, jika tidak topeng / me-reset kode keluar sebelumnya.

command_last () {
  echo "True is `true`"
  echo "False is `false`"
  false
}
command_last; echo $?
# Outputs:
# True is 0
# False is 1
# 1

echo_last () {
  echo "True is `true`"
  echo "False is `false`"
  false
  # echo'ing literally anything (or nothing) returns true aka exit 0
  echo
}
echo_last; echo $?
# Outputs:
# True is 0
# False is 1
#            # Blank line due to empty echo
# 0

Akhirnya trik kotor karena Anda tidak dapat melakukannya VAR=(SOME_COMMAND)karena VAR=()merupakan definisi array sehingga Anda perlu VAR=( $(echo 'Some value') ).

dragon788
sumber
Semua output yang diklaim salah, karena fakta bahwa substitusi perintah tidak memberikan kode keluar, yang merupakan inti dari pertanyaan. Tidak jelas apa hubungan "trik kotor" dengan apa pun.
Nick Matteo