Bagaimana cara membuat `local` menangkap kode keluar?

11

Dalam proyek saya, saya memiliki cuplikan berikut:

local output="$(bash "${1##*/}")"
echo "$?"

Ini selalu mencetak nol karena local, bagaimanapun, menghapus localmenyebabkan $?variabel berperilaku dengan benar: yang mengasumsikan kode keluar dari subkulit.

Pertanyaan saya adalah: bagaimana saya bisa menjaga variabel ini tetap lokal sementara juga menangkap nilai keluar?

Elang Tertinggi
sumber
1
shellchecktidak hanya akan menangkap masalah ini tetapi menyarankan solusinya di unix.stackexchange.com/a/281749/24718 !
Waleed Khan

Jawaban:

16
#!/bin/bash
thing() {
   local foo=$(asjkdh) ret="$?"
   echo "$ret"
}

Ini akan bergema 127, kode kesalahan yang benar untuk "perintah tidak ditemukan".

Anda dapat menggunakan localuntuk mendefinisikan lebih dari satu variabel. Jadi saya juga membuat variabel lokal RETuntuk mengambil kode keluar dari subkulit sebelum localberhasil dan set $?ke nol.

DopeGhoti
sumber
Apakah dijamin bashmenilai ekspresi ini dari kiri ke kanan?
Max Ried
Sejauh yang saya ketahui, tugas variabel dalam urutan, kiri ke kanan dalam konteks ini, ya.
DopeGhoti
@ MaxRied fakta ini berfungsi andal akan muncul untuk menunjukkan bahwa ya, itu. Namun, saya tidak dapat menemukan informasi tentang ini baik dari bashmanual referensi POSIX maupun .
kucing
10
Selain itu, menggunakan nama variabel all-caps adalah bentuk yang buruk. Lihat spesifikasi variabel lingkungan POSIX di pubs.opengroup.org/onlinepubs/009695399/basedefs/… , yang menjelaskan nama semua huruf besar sebagai variabel yang dicadangkan untuk variabel dengan makna pada shell atau sistem dan nama dengan setidaknya satu karakter huruf kecil dicadangkan untuk penggunaan yang ditentukan aplikasi, mengingat bahwa variabel shell dan variabel lingkungan berbagi namespace (karena, jika terjadi tabrakan, penugasan ke yang pertama dapat menggantikan yang terakhir).
Charles Duffy
Komentar bukan untuk diskusi panjang; percakapan ini telah dipindahkan ke obrolan .
terdon
27

Nyatakan variabel lokal sebelum Anda menetapkannya:

thing() {
  local output
  output="$(bash "${1##*/}")"
  echo "$?"
}

Menurut pendapat saya ini juga lebih mudah dibaca daripada mengatur RETvariabel tambahan . YMMV tentang itu, tetapi berfungsi seperti yang Anda harapkan.

Wildcard
sumber
2
Ini jauh lebih baik daripada menggunakan variabel terpisah, seperti yang seharusnya jelas jika Anda ingin memeriksa kode pengembalian beberapa tugas: cukup local var1 var2 ...dan Bob adalah paman Anda.
l0b0
@ 10B0 Bob adalah pamanku. : D
cat