Apakah mungkin untuk menjaga status keluar perintah terakhir ( $?
) tidak berubah setelah pengujian?
Misalnya, saya ingin melakukan:
command -p sudo ...
[ $? -ne 1 ] && exit $?
Yang terakhir exit $?
harus mengembalikan status keluar sudo, tetapi sebaliknya ia selalu mengembalikan 0
(kode keluar dari tes).
Apakah mungkin untuk melakukan itu tanpa variabel sementara?
Contoh lain untuk memperjelas lebih lanjut:
spd-say "$@"
[ $? -ne 127 ] && exit $?
Dalam hal ini saya ingin keluar hanya jika perintah pertama ditemukan (kode keluar! = 127
). Dan saya ingin keluar dengan spd-say
kode keluar yang sebenarnya (mungkin tidak
0
).
EDIT: Saya lupa menyebutkan bahwa saya lebih suka solusi pengaduan POSIX untuk portabilitas yang lebih baik.
Saya menggunakan konstruksi ini dalam skrip di mana saya ingin memberikan alternatif untuk perintah yang sama. Misalnya, lihat skrip crc32 saya .
Masalah dengan variabel sementara adalah mereka bisa membayangi variabel lain, dan untuk menghindari itu Anda harus menggunakan nama panjang, yang tidak baik untuk keterbacaan kode.
sumber
if ! command -p sudo; then exit; fi
yang memiliki hasil yang sama untuk contoh Anda.[ $? -ne 127 ] && exit $?
)sudo
perintah berhasil (yaitu, jikasudo
keluar dengan status 0). Tapi, dalam kode Anda, skrip tetap berjalan (tidak keluar) jikasudo
berhasilcommand
dan tidaksudo
sama sekali. Itulah yang dimaksud dengan saya ingin keluar hanya jika perintah pertama ditemukan (kode keluar! = 127) dan merupakan pengembalian yang ditentukancommand
ketika perintah yang diminta tidak ditemukan. Saya kira masalahnya adalah bahwa memohonsudo
sebagai bagian dari tes memungkinkan untuksudo
menekan kembalicommand
di tempat pertama dan jadi miring tes.Jawaban:
$_
akan bekerja di (setidaknya) interaktifdash
,bash
,zsh
,ksh
(meskipun tampaknya tidak dalam sebuah pernyataan kondisional seperti yang diminta) danmksh
kerang. Dari mereka - setahu saya - hanyabash
danzsh
akan mengisi itu dalam shell scripted. Ini bukan parameter POSIX - tetapi cukup portabel untuk shell interaktif modern.Untuk solusi yang lebih portabel yang dapat Anda lakukan:
Yang pada dasarnya memungkinkan Anda untuk memperluas nilai awal
$?
ke bagian ujung skrip sebelum bahkan menguji nilainya di kepalanya.Tapi bagaimanapun, karena Anda tampaknya menguji apakah perintah tersebut
sudo
dapat ditemukan dalam string-p
path portabel bawaan shellcommand
, saya akan berpikir Anda bisa melakukannya secara langsung. Juga, hanya untuk menjadi jelas,command
tidak akan menguji lokasi argumen untuksudo
- jadi hanyasudo
- dan tidak ada yang diminta - yang relevan dengan nilai pengembalian.Lagi pula, jika itu yang Anda coba lakukan:
... akan berfungsi dengan baik sebagai tes tanpa ada kemungkinan kesalahan dalam
sudo
menjalankan perintah kembali sedemikian rupa yang dapat membelokkan hasil pengujian Anda.sumber
Ada berbagai opsi untuk menangani status keluar secara andal tanpa overhead, tergantung pada persyaratan aktual.
Anda dapat menyimpan status keluar menggunakan variabel:
Anda dapat langsung memeriksa keberhasilan atau kegagalan:
Atau gunakan
case
konstruk untuk membedakan status keluar:dengan kasus khusus yang ditanyakan dalam pertanyaan:
Semua opsi tersebut memiliki keunggulan yang sesuai dengan standar POSIX.
(Catatan: Untuk ilustrasi saya menggunakan
echo
perintah di atas; ganti denganexit
pernyataan yang sesuai untuk mencocokkan fungsi yang diminta.)sumber
("$(get_errnos)")
adalah tambahan buatan substitusi perintah di mana perbandingan dengan kode kesalahan aktual diminta dalam pertanyaan, 2.) Ada jelas dalam standar apa yang berubah$?
(dan dengan demikian apa yang tidak mengubahnya), dan 3.) ada tidak ada efek samping dengan konstruk itu (kecuali, seperti yang Anda lakukan, Anda memperkenalkannya secara tidak perlu). - OTOH, karena Anda keberatan, jawaban lain yang Anda sukai jelas tidak standar.$(get_errnos)
kode buatan yang sama ke solusi lain (( exit 42 ); test "$(get_errnos)" -ne $? && echo $_
) mereka juga tidak berfungsi. (Anda lebih suka membawa solusi standar saya dalam kesalahan kredit, bukan peretasan non-standar lainnya .) - Tentu saja Anda dapat menambahkan kode arbitrer ke setiap jawaban dan merusaknya. - Dan WRT untuk perubahan$?
; hanya karena Anda tidak dapat menemukannya bukan berarti itu tidak benar. (Saya sudah memberikan dalam diskusi kami bahkan kata kunci untuk dicari di POSIX.)zsh
( disebutkan pertama saja; kemudian Anda menambahkan jugadash
) bahwa saya pikir itu pasti bug di sana, mengingat bahwacase
status keluar dan pengaturan$?
tampaknya didefinisikan dengan baik dalam POSIX. - Dan juga di sini, sekali lagi, Anda menerapkan standar ganda; peretasan lainnya, misalnya, bukan merupakan standar, juga tidak dapat dipercaya bekerja di shell standar lainnya (misalnya tidak dalamksh
). - Proposal saya standar dan berfungsibash
(kebanyakan digunakan di Linux) danksh
(shell dominan di Unix komersial).Gunakan
$_
, yang memperluas argumen terakhir dari perintah sebelumnya.sumber
$?
dan$_
referensi. IMHO lebih baik untuk tetap pada metode yang konsisten yang bekerja dalam kasus lain (dan juga dapat membantu dengan keterbacaan kode).case
pola , satu-satunya tempat yang penting dalam teori (tetapi tidak dalam pertanyaan yang diberikan), adalah kasus yang dikonstruksi. - Bagaimanapun, substitusi perintah shell Anda akan menyebarkan hasil dari perintah yang disematkan, biasanya ekspansi lainnya tidak akan memengaruhi status pengembalian jika tidak ada perintah yang terlibat yang dapat membuat kesalahan (x=${a!b}
kasus pikiran , tetapi tidak relevan di sini). - Apa yang Anda maksud dengan "perintah tanpa nama perintah" ?Anda dapat mendefinisikan (dan menggunakan) fungsi shell:
Kemudian
Bisa dibilang, ini "curang", karena itu membuat salinan
$?
dalamcheck_exit_status
daftar argumen.Ini mungkin terlihat agak canggung, dan memang begitu. (Itu kadang-kadang terjadi ketika Anda memaksakan batasan sewenang-wenang pada masalah.) Ini mungkin tampak tidak fleksibel, tetapi tidak. Anda dapat membuat
check_exit_status
lebih kompleks, menambahkan argumen yang memberi tahu tes apa yang harus dilakukan pada nilai status keluar.sumber
Untuk menjawab pertanyaan langsung Anda, tidak, tidak mungkin untuk tetap
$?
tidak berubah. Dan ini adalah salah satu kasus di mana saya curiga Anda berfokus pada masalah yang salah. Variabel sementara adalah cara standar dan disukai untuk mendapatkan efek yang Anda cari. Ini sangat standar sehingga saya menyarankan untuk meninggalkan (atau memikirkan kembali) alasan apa pun yang Anda pikir Anda miliki karena tidak ingin menggunakannya; Saya sangat ragu bahwa itu sepadan dengan kompleksitas tambahan yang ditambahkan oleh metode lain.Jika Anda hanya bertanya karena penasaran, maka jawabannya adalah tidak.
sumber
$?
atau sesuatu seperti ituBerikut cuplikan kode saya untuk mempertahankan status keluar sebelumnya tanpa keluar dari skrip / shell saat ini
sumber