Saya mengalami beberapa masalah aneh dengan bash belakangan ini. Saat mencoba menyederhanakan skrip saya, saya membuat sepotong kecil kode ini:
$ o(){ echo | while read -r; do return 0; done; echo $?;}; o
0
$ o(){ echo | while read -r; do return 1; done; echo $?;}; o
1
return
seharusnya keluar dari fungsi tanpa mencetak $?
, bukan? Baiklah, kemudian saya memeriksa apakah saya dapat kembali dari pipa sendirian:
$ echo | while read -r; do return 1; done
bash: return: can only `return' from a function or sourced script
Hal yang sama terjadi tanpa while
loop:
$ foo(){ : | return 1; echo "This should not be printed.";}
$ foo
This should not be printed.
Apakah ada sesuatu yang saya lewatkan di sini? Pencarian Google tidak menghasilkan apa-apa tentang ini! Versi bash saya adalah 4.2.37 (1) - dirilis di Debian Wheezy.
bash
shell-script
pipe
subshell
Teresa e Junior
sumber
sumber
while
tidak diperlukan untuk reproduksi? Itu mengalihkan perhatian dari intinya.while
Loop adalah penggunaan yang sangat umum untuk pipareturn
. Contoh kedua lebih langsung ke titik, tetapi itu adalah sesuatu yang saya tidak percaya ada yang akan menggunakan ...Jawaban:
Terkait: /programming//a/7804208/4937930
Ini bukan bug yang Anda tidak bisa keluar dari skrip atau kembali dari fungsi oleh
exit
ataureturn
dalam subshell. Mereka dieksekusi dalam proses lain dan tidak mempengaruhi proses utama.Selain itu, saya kira Anda melihat perilaku bash tidak terdokumentasi pada (mungkin) spec yang tidak terdefinisi. Dalam suatu fungsi, tidak ada kesalahan yang ditegaskan
return
di tingkat atas perintah subshell dan itu hanya berperilaku sepertiexit
.IMHO itu bug bash untuk perilaku tidak konsisten
return
tergantung pada apakah pernyataan utama dalam suatu fungsi atau tidak.Keluaran:
sumber
return
tidak bekerja dari urutan perintah tingkat atas dalam subkulit, dan khususnya tidak keluar dari subkulit, adalah apa yang sudah membuat saya berharap dokumen yang ada. OP dapat menggunakanexit 1 || return 1
tempat mereka mencoba menggunakanreturn
, dan kemudian harus mendapatkan perilaku yang diharapkan. EDIT: @ herbert jawaban menunjukkan bahwa tingkat atasreturn
dalam subkulit berfungsi sebagaiexit
(tetapi hanya dari subkulit).return
dalam urutan subshell sederhana harus dinyatakan sebagai kesalahan runtime dalam kasus apa pun , tetapi sebenarnya tidak ketika itu terjadi di sebuah fucntion. Masalah ini juga telah dibahas di gnu.bash.bug , tetapi tidak ada kesimpulan.return
pernyataan itu dalam fungsi dan dengan demikian legal. Namun perilaku yang dihasilkan tidak ditentukan.Ini bukan bug di dalam
bash
tetapi perilaku yang didokumentasikan :The
return
instruksi makhluk berlaku di dalam definisi fungsi tetapi berada di subkulit juga, itu tidak mempengaruhi shell induknya sehingga instruksi berikutnya,echo
, dijalankan terlepas. Namun demikian, ini adalah konstruksi shell yang tidak portabel karena standar POSIX memungkinkan perintah-perintah yang menyusun pipa untuk dieksekusi baik dalam subkulit (default) atau yang atas (ekstensi yang diizinkan).Semoga, Anda dapat memberi tahu
bash
untuk berperilaku seperti yang Anda harapkan dengan beberapa pilihan:sumber
return
tidak akan keluar dari fungsi, tidakkah akan lebih masuk akal jika shell hanya dicetakbash: return: can only `return' from a function or sourced script
, alih-alih memberi pengguna perasaan palsu bahwa fungsi tersebut mungkin telah kembali?return
dari subkulit. Setelah semua, ia tahu bahwa itu dalam subkulit, sebagaimana dibuktikan oleh$BASH_SUBSHELL
variabel. Masalah terbesar adalah bahwa ini dapat mengarah pada positif palsu; seorang pengguna yang mengerti bagaimana subkulit bekerja dapat memiliki skrip tertulis yang digunakanreturn
sebagai penggantiexit
untuk mengakhiri sebuah subkulit. (Dan, tentu saja, ada kasus yang valid di mana orang mungkin ingin mengatur variabel atau melakukancd
subkulit.)return
kembali dari subkulit bukannya gagal, karena berada di dalam fungsi aktual. Masalahnya adalah bahwahelp return
secara khusus menyatakan:Causes a function or sourced script to exit with the return value specified by N.
Dari membaca dokumentasi, setiap pengguna akan mengharapkannya setidaknya gagal atau mencetak peringatan, tetapi tidak pernah berperilaku sepertiexit
.return
dalam subkulit dalam fungsi untuk kembali dari fungsi (dalam proses shell utama) tidak mengerti subkulit dengan sangat baik. Sebaliknya, saya akan mengharapkan pembaca yang mengerti subkulit untuk mengharapkanreturn
dalam subkulit dalam fungsi untuk mengakhiri subkulit, sama seperti yangexit
akan.Per dokumentasi POSIX, menggunakan di
return
luar fungsi atau skrip bersumber tidak ditentukan . Jadi, itu tergantung pada cangkang Anda untuk menangani.Shell SystemV akan melaporkan kesalahan, sementara di
ksh
, direturn
luar fungsi atau skrip bersumber sepertiexit
. Kebanyakan shell POSIX dan osh schily juga berperilaku seperti itu:ksh
danzsh
tidak menghasilkan karena bagian terakhir dari pipa di shell ini dieksekusi di shell saat ini, bukan subshell. Pernyataan pengembalian mempengaruhi lingkungan shell saat ini yang disebut fungsi, menyebabkan fungsi kembali segera tanpa mencetak apa pun.Dalam sesi interaktif,
bash
hanya laporkan kesalahan tetapi tidak menghentikan shell,schily's osh
melaporkan kesalahan dan menghentikan shell:(
zsh
dalam sesi interaktif dan output terminal tidak dihentikanbash
,,yash
danschily's osh
melaporkan kesalahan tetapi tidak menghentikan shell)sumber
return
digunakan di dalam suatu fungsi di sini.return
digunakan di dalam fungsi subshell inside , kecuali dan .ksh
zsh
Saya pikir Anda mendapatkan perilaku yang diharapkan, dalam bash, setiap perintah dalam pipa dieksekusi dalam subkulit. Anda dapat mengabdikan diri dengan mencoba mengubah variabel global fungsi Anda:
Ngomong-ngomong, kembalinya bekerja tetapi kembali dari subkulit. Sekali lagi Anda dapat memeriksa bahwa:
Akan menampilkan yang berikut:
Jadi, pernyataan pengembalian dengan benar keluar dari subkulit
.
sumber
foo(){ : | return 1 || return 2; echo$?; echo "This should not be printed.";}; foo; echo $?
dan Anda akan mendapatkan hasil2
. Tapi untuk kejelasan saya akan membuatreturn 1
beexit 1
.Jawaban yang lebih umum adalah bahwa bash dan beberapa cangkang lain biasanya meletakkan semua elemen pipa ke dalam proses yang terpisah. Ini wajar ketika baris perintah
karena program biasanya dijalankan dalam proses yang terpisah pula (kecuali jika Anda mengatakan ). Tapi itu bisa mengejutkan
exec program
di mana beberapa atau semua perintah adalah perintah bawaan. Contoh sepele meliputi:
Contoh yang sedikit lebih realistis adalah
di mana seluruh
while
...do
...done
loop dimasukkan ke dalam subproses, dan perubahannya menjadit
tidak terlihat oleh shell utama setelah loop berakhir. Dan itulah yang Anda lakukan - memipis ke dalam sebuahwhile
loop, menyebabkan loop berjalan sebagai subkulit, dan kemudian mencoba untuk kembali dari subkulit.sumber