Perbedaan antara kembali dan keluar dalam fungsi Bash

429

Apa perbedaan antara pernyataan returndan exitdalam fungsi Bash sehubungan dengan kode keluar?

lecodesportif
sumber
55
Protip: ketik help <command>shell Anda untuk mendapatkan info tentang apa yang akan dilakukan oleh shell builtin. Dalam kasus Anda help returndanhelp exit
SiegeX

Jawaban:

318

Dari man bashpada return [n];

Menyebabkan fungsi berhenti mengeksekusi dan mengembalikan nilai yang ditentukan oleh n ke pemanggilnya. Jika n dihilangkan, status kembali adalah bahwa dari perintah terakhir yang dijalankan di badan fungsi.

... pada exit [n]:

Menyebabkan shell keluar dengan status n. Jika n dihilangkan, status keluar adalah dari perintah terakhir yang dijalankan. Jebakan pada EXIT dieksekusi sebelum shell berakhir.

EDIT:

Sesuai dengan pengeditan pertanyaan Anda, mengenai kode keluar, returntidak ada hubungannya dengan kode keluar. Kode keluar dimaksudkan untuk aplikasi / skrip , bukan fungsi. Jadi dalam hal ini, satu-satunya kata kunci yang menetapkan kode keluar dari skrip (salah satu yang dapat ditangkap oleh program panggilan menggunakan $?variabel shell) adalah exit.

EDIT 2:

Mengacu pernyataan terakhir saya exitmenyebabkan beberapa komentar. Itu dibuat untuk membedakan returndan exituntuk memahami OP, dan pada kenyataannya, pada setiap titik tertentu dari program / script shell, exitsatu-satunya cara mengakhiri script dengan kode keluar untuk proses menelepon.

Setiap perintah yang dijalankan di shell menghasilkan "kode keluar" lokal: ia menetapkan $?variabel ke kode itu, dan dapat digunakan bersama if, &&dan operator lain untuk menjalankan perintah lain secara kondisional.

Kode keluar ini (dan nilai $?variabel) diatur ulang oleh setiap eksekusi perintah.

Kebetulan, kode keluar dari perintah terakhir yang dijalankan oleh skrip digunakan sebagai kode keluar dari skrip itu sendiri seperti yang terlihat oleh proses pemanggilan.

Akhirnya, fungsi, ketika dipanggil, bertindak sebagai perintah shell sehubungan dengan keluar dari kode. Kode keluar dari fungsi ( dalam fungsi) diatur dengan menggunakan return. Jadi ketika dalam suatu fungsi return 0dijalankan, eksekusi fungsi berakhir, memberikan kode keluar 0.

Diego Sevilla
sumber
10
Tidak persis. Itu selalu mengembalikan nilai dari shell saat ini. Tidak masalah apakah Anda berada di dalam suatu fungsi atau tidak.
Diego Sevilla
10
Komentari hasil edit Anda: Saya mungkin membingungkan mengembalikan nilai dan kode keluar, tetapi func(){ return 50; };func;echo $?menggemakan 50. Jadi $?variabel shell tampaknya tidak terbatas exit.
lecodesportif
8
" $?Perluas ke status keluar dari pipa depan yang baru saja dieksekusi." Keluar itu mungkin dari shell dalam bentuk panggilan ke exit(atau memukul akhir skrip) atau dalam bentuk panggilan ke returndalam suatu fungsi.
SiegeX
11
@ lecodesportif: Skrip $? proses / skrip saat ini terbatas pada exitatau pada hasil dari perintah terakhir yang dijalankan oleh skrip ini. Jadi, jika baris skrip terakhir Anda adalah panggilan ke fungsi itu, dan fungsi itu mengembalikan 50, ya, $?yang Anda hasilkan untuk proses yang memanggil Anda adalah 50. Namun, itu tidak ada hubungannya dengan return, karena ini adalah terbatas pada skrip saat ini. Kebetulan dikembalikan hanya jika pemanggilan fungsi ini adalah kalimat terakhir dari skrip. exitNamun, selalu selesaikan skrip dan kembalikan nilai itu $? ke proses pemanggilan .
Diego Sevilla
11
-1 untuk membingungkan saya dengan baris " returntidak ada hubungannya dengan kode keluar." Eksperimen memberi tahu saya bahwa tidak ada perbedaan fungsional antara kode kembali fungsi dan kode keluar skrip.
Jack
296

returnakan menyebabkan fungsi saat ini keluar dari ruang lingkup, sementara exitakan menyebabkan skrip berakhir pada titik di mana ia dipanggil. Berikut adalah contoh program untuk membantu menjelaskan ini:

#!/bin/bash

retfunc()
{
    echo "this is retfunc()"
    return 1
}

exitfunc()
{
    echo "this is exitfunc()"
    exit 1
}

retfunc
echo "We are still here"
exitfunc
echo "We will never see this"

Keluaran

$ ./test.sh
this is retfunc()
We are still here
this is exitfunc()
SiegeX
sumber
17
Contoh yang bagus. Anda juga bisa menampilkan nilai keluar 1 in $?.
Diego Sevilla
48
Perhatikan bahwa fungsi ini TIDAK akan mencetak "Kami masih di sini" jika Anda menambahkan "set -e" sebelum panggilan ke "retfunc".
Michael
4
Namun, echo fnord | while read x; do exitfunc; done; echo "still here"akan mencetak "masih di sini". Tampaknya hanya whilesub-shell yang keluar dalam skenario ini.
tripleee
Solusi yang mendekati adalah done || exit $?tetapi itu jelek dan tidak persis setara.
tripleee
2
+1 Mungkin bermanfaat untuk menambahkan: `` ` returnakan menyebabkan fungsi atau skrip bersumber saat ini keluar dari ruang lingkup```.
Isaac
56

Saya tidak berpikir ada orang yang benar-benar menjawab pertanyaan karena mereka tidak menjelaskan bagaimana keduanya digunakan. OK saya pikir kita tahu bahwa exit membunuh skrip, di mana pun skrip dipanggil dan Anda dapat menetapkan statusnya juga seperti keluar atau keluar 0 atau keluar 7 dan seterusnya. Ini dapat digunakan untuk menentukan bagaimana skrip dipaksa berhenti jika dipanggil oleh skrip lain dll. Cukup saat keluar.

kembali ketika dipanggil akan mengembalikan nilai yang ditentukan untuk menunjukkan perilaku fungsi, biasanya 1 atau 0. Sebagai contoh:

    #!/bin/bash
    isdirectory() {
      if [ -d "$1" ]
      then
        return 0
      else
        return 1
      fi
    echo "you will not see anything after the return like this text"
    }

periksa seperti ini:

    if isdirectory $1; then echo "is directory"; else echo "not a directory"; fi

atau seperti ini:

    isdirectory || echo "not a directory"

Dalam contoh ini, tes dapat digunakan untuk menunjukkan apakah direktori itu ditemukan. perhatikan bahwa apa pun setelah pengembalian tidak akan dieksekusi dalam fungsi. 0 benar tetapi salah 1 dalam shell, berbeda dari prog langs lainnya.

Untuk info lebih lanjut tentang fungsi: http://www.linuxjournal.com/content/return-values-bash-functions

CATATAN: Fungsi direktori adalah hanya untuk keperluan pengajaran. Seharusnya ini bukan cara Anda melakukan opsi seperti itu dalam skrip nyata.

Mike Q
sumber
3
Atau gunakan saja test -d $1untuk mencapai hasil yang sama. Tidak pernah melakukannya if <check> return else return. <check>sendirian akan melakukan hal yang sama dalam semua bahasa yang saya tahu setidaknya.
erikbwork
4
Untuk menjadi lebih eksplisit tentang apa yang dikatakan erik: isdirectory() { [ -d "$1" ]; }akan berperilaku persis sama dengan apa yang Anda miliki di sini: Nilai pengembalian default dari fungsi shell, apakah dengan mencapai akhir kode atau returndengan tanpa argumen, adalah dari perintah terbaru.
Charles Duffy
11
Komentator lain di sini mengkritik gaya contoh Mike Q, ketika dia benar-benar berbicara tentang perilaku returnpernyataan itu. Memang benar bahwa contohnya sederhana dan tidak digunakan dalam produksi. Tapi itu sederhana, jadi itu menyelesaikan tugasnya dengan baik. Tidak ada yang salah dengan itu.
Mike S
Terima kasih Mike S, ya saya setuju bahwa contoh paling sederhana menjelaskan keluar dan kembali. Komentar lain tentu saja valid, dan harus dipertimbangkan untuk coders bash yang lebih canggih ;-)
Mike Q
1
Beberapa orang mungkin mengatakan itu tidak terkait dengan pertanyaan itu, tetapi itu berhubungan dengan dan menjawab masalah yang saya alami yang membuat saya menemukan Pertanyaan ini. :-)
Jesse Steele
33

Ingat, fungsi internal ke skrip dan biasanya kembali dari mana mereka dipanggil dengan menggunakan pernyataan kembali. Memanggil skrip eksternal adalah masalah lain sepenuhnya, dan skrip biasanya berakhir dengan pernyataan keluar.

Perbedaan "antara pernyataan kembali dan keluar dalam fungsi BASH sehubungan dengan kode keluar" sangat sedikit. Keduanya mengembalikan status, bukan nilai per se. Status nol menunjukkan keberhasilan, sementara status lainnya (1 hingga 255) menunjukkan kegagalan. Pernyataan pengembalian akan kembali ke skrip dari mana ia dipanggil, sedangkan pernyataan keluar akan mengakhiri seluruh skrip dari mana pun itu ditemui.

return 0  # returns to where the function was called.  $? contains 0 (success).

return 1  # returns to where the function was called.  $? contains 1 (failure).

exit 0  # exits the script completely.  $? contains 0 (success).

exit 1  # exits the script completely.  $? contains 1 (failure).

Jika fungsi Anda berakhir tanpa pernyataan pengembalian, status perintah terakhir yang dijalankan dikembalikan sebagai kode status (dan akan ditempatkan di $?).

Ingat, kembali dan keluar, berikan kembali kode status dari 0 hingga 255, tersedia di $?. Anda tidak dapat memasukkan hal lain ke dalam kode status (mis. Mengembalikan "cat"); itu tidak akan bekerja. Tetapi, sebuah skrip dapat mengembalikan 255 alasan berbeda untuk kegagalan dengan menggunakan kode status.

Anda dapat mengatur variabel yang terkandung dalam skrip panggilan, atau hasil gema dalam fungsi dan menggunakan substitusi perintah dalam skrip panggilan; tetapi tujuan kembali dan keluar adalah untuk lulus kode status, bukan nilai atau hasil perhitungan seperti yang mungkin diharapkan dalam bahasa pemrograman seperti C.

pengguna2100135
sumber
25

Terkadang, Anda menjalankan skrip menggunakan .atau source.

. a.sh

Jika Anda memasukkan exitdalam a.sh, itu tidak hanya akan menghentikan skrip, tetapi mengakhiri sesi shell Anda.

Jika Anda memasukkan returndalam a.sh, itu hanya berhenti memproses skrip.

Juraj
sumber
1
Tetapi ketika saya menjalankan a.sh saya mendapatkan kesalahan return: can only 'return' from a function or sourced script, yang membuatnya tidak cocok untuk skrip umum.
Peter - Pasang kembali Monica
Pada level teratas dalam skrip, tidak ada yang cocok dalam allsituasi. Menggunakan .atau sourcemenjalankan skrip di shell saat ini, alih-alih menghasilkan sub-shell. Script harus tahu bagaimana cara menggunakannya. Celakalah pengguna yang melakukannya secara berlawanan. Secara pribadi, saya sarankan membaca skrip sebelum menjalankannya pertama kali.
Jesse Chisholm
3
Trik luar biasa yang saya temui adalah menggunakan trapfungsi untuk ERR EXITdan kemudian pertama-tama menyimpan kode keluar dari perintah yang gagal errCode=$?dan kemudian keluar dari skrip (bersumber atau tidak) dengan return $errCode || exit $errCodemana ||artinya "jika saya tidak dapat kembali karena saya tidak bersumber , keluar saja sebagai gantinya ".
dragon788
6

Dengan kata-kata sederhana (terutama untuk pemula dalam pengkodean), kita dapat mengatakan,

`return` : exits the function,
`exit()` : exits the program(called as process while running)

Juga Jika Anda mengamati, ini sangat mendasar tapi ...,

`return` : is the keyword
`exit()` : is the function
Jyo si Whiff
sumber
1
Dalam skrip bash, exittidak lebih dari fungsi return. Mereka adalah perintah bawaan. Mereka bahkan bukan kata-kata yang dicadangkan.
Peter - Reinstate Monica
6
  • exitmenghentikan proses saat ini ; dengan atau tanpa kode keluar, anggap ini sistem lebih dari sekadar fungsi program. Perhatikan bahwa saat sumber, exitakan mengakhiri shell, namun, saat menjalankan hanya akan exitskrip.

  • returndari fungsi, kembali ke instruksi setelah panggilan, dengan atau tanpa kode kembali. returnbersifat opsional dan tersirat di akhir fungsi. returnhanya dapat digunakan di dalam suatu fungsi.

Saya ingin menambahkan bahwa saat bersumber, tidak mudah untuk exitskrip dari dalam suatu fungsi tanpa membunuh shell. Saya pikir, contoh lebih baik pada skrip 'tes'

#!/bin/bash
function die(){
   echo ${1:=Something terrible wrong happen}
   #... clean your trash
   exit 1
}

[ -f /whatever/ ] || die "whatever is not available"
# now we can proceed
echo "continue"

lakukan hal berikut:

user$ ./test
Whatever is not available
user$

test -dan- cangkangnya akan menutup.

user$ . ./test
Whatever is not available

hanya testakan selesai dan prompt akan ditampilkan.

Solusinya adalah dengan melampirkan prosedur potensial di (dan)

#!/bin/bash
function die(){
   echo $(1:=Something terrible wrong happen)
   #... clean your trash
   exit 1
}

( # added        
    [ -f /whatever/ ] || die "whatever is not available"
    # now we can proceed
    echo "continue"
) # added

sekarang, dalam kedua kasus hanya testakan keluar.

fcm
sumber
Menambahkan (dan )meletakkan blok itu di sub-shell, secara efektif membatalkan perintah .(sumber) seolah-olah Anda telah menjalankan skrip tes secara normal, yang berada di dalam sub-shell. Jika script tidak berjalan dengan .atau sourceAnda secara efektif memiliki 2 sub-shell.
Jesse Chisholm
3

Pertanyaan OP: Apa perbedaan antara pernyataan kembali dan keluar dalam fungsi BASH sehubungan dengan kode keluar?

Tiga puluh, beberapa klarifikasi diperlukan:

  • Pernyataan (kembali | keluar) tidak diperlukan untuk menghentikan eksekusi (fungsi | shell). A (function | shell) akan berakhir ketika mencapai akhir daftar kodenya, bahkan tanpa pernyataan (kembali | keluar).
  • Pernyataan (kembali | keluar) tidak diharuskan untuk mengembalikan nilai dari yang diakhiri (fungsi | shell). Setiap proses memiliki variabel bawaan $? yang selalu memiliki nilai numerik. Ini adalah variabel khusus yang tidak dapat diatur seperti "? = 1", tetapi hanya diatur dengan cara khusus (lihat di bawah *). Nilai $? setelah perintah terakhir yang akan dieksekusi di (disebut function | sub shell) adalah nilai yang dilewatkan kembali ke (function caller | parent shell). Itu benar apakah perintah terakhir yang dijalankan adalah ("return [n]" | "exit [n]") atau plain ("return" atau sesuatu yang lain yang merupakan perintah terakhir dalam kode fungsi yang dipanggil.

Dalam daftar bullet di atas, pilih dari "(x | y)" selalu item pertama atau selalu item kedua untuk mendapatkan pernyataan tentang fungsi & kembali atau masing-masing shell & keluar.

Yang jelas keduanya sama-sama menggunakan variabel khusus $ $? untuk meneruskan nilai ke atas setelah berakhir.

* Sekarang untuk cara khusus yang $? dapat diatur:

  • Ketika fungsi yang dipanggil berakhir dan kembali ke pemanggil itu lalu $? di pemanggil akan sama dengan nilai akhir $? dalam fungsi yang dihentikan.
  • Ketika sebuah shell induk secara implisit atau eksplisit menunggu pada satu sub shell dan dilepaskan oleh terminasi sub shell tersebut, maka $? di shell induk akan sama dengan nilai akhir $? di sub shell yang dihentikan.
  • Beberapa fungsi bawaan dapat memodifikasi $? tergantung pada hasil mereka. Tetapi beberapa tidak.
  • Fungsi bawaan "kembali" dan "keluar", bila diikuti oleh argumen numerik keduanya $? dengan argumen, dan mengakhiri eksekusi.

Perlu dicatat bahwa $? dapat diberi nilai dengan memanggil exit di sub shell, seperti ini:

# (exit 259)
# echo $?
3  
Craig Hicks
sumber
4
Dalam hal beberapa melewatkannya, exit 259gema 3karena nilai keluar akhir adalah satu byte. 259 % 256 = 3
Jesse Chisholm
0

Pertama-tama, returnadalah kata kunci dan exitteman saya adalah fungsi.

Yang mengatakan, inilah penjelasan paling sederhana.

return Ini mengembalikan nilai dari suatu fungsi.

exit Itu keluar dari atau meninggalkan shell saat ini.

Ahmad Awais
sumber
Tidak juga! Secara logika Anda salah. Keluar adalah fungsi sedangkan returnkata kunci. Pengembalian lebih dari sekedar kode keluar yang mengapa perbandingannya tidak adil.
Ahmad Awais
Saya telah mengeditnya untuk membuat poin lebih jelas yang saya coba buat. Terima kasih telah membantu saya melakukan itu.
Ahmad Awais
4
Juga exittidak returnada "kata kunci", atau, sebagaimana manual bash menyebutnya, "kata-kata yang dicadangkan". Tidak ada yang merupakan "fungsi" baik, dalam arti fungsi bash. Keduanya adalah perintah builtin, dalam istilah bash. (Ada adalah fungsi standar C library disebut exit(), dan bahasa pemrograman C memiliki kata reserved return, tetapi mereka tidak harus bingung dengan perintah bash, meskipun semantik mereka ingin tahu serupa.)
Peter - mengembalikan Monica