Cara apa pun untuk keluar dari skrip bash, tetapi tidak keluar dari terminal

183

Ketika saya menggunakan exitperintah dalam skrip shell, skrip akan mengakhiri terminal (prompt). Apakah ada cara untuk mengakhiri skrip dan kemudian tinggal di terminal?

Skrip saya run.shdiharapkan untuk dieksekusi dengan bersumber langsung, atau bersumber dari skrip lain.

EDIT: Untuk lebih spesifik, ada dua skrip run2.shsebagai

...
. run.sh
echo "place A"
...

dan run.shsebagai

...
exit
...

ketika saya menjalankannya . run2.sh, dan jika masuk exitcodeline run.sh, saya ingin berhenti di terminal dan tinggal di sana. Tetapi menggunakan exit, seluruh terminal ditutup.

PS: Saya sudah mencoba menggunakan return, tetapi echocodeline masih akan dieksekusi ....

Richard
sumber
5
Saya benar-benar harus bertanya: mengapa Anda menggunakan exit dalam skrip bersumber?
Ignacio Vazquez-Abrams
3
perintah keluar seharusnya tidak mengakhiri sesi terminal / login Anda. jika Anda menggunakan exit 0untuk menghentikan skrip setelah sukses, ketika Anda menjalankan skrip Anda ex: ./test.shAnda akan melihat output tetapi konsol Anda akan tetap terbuka.
Ben Ashton
Anda bisa menggunakan shellperintah, yang sebenarnya membuka terminal shell. Namun pengalaman saya sendiri adalah bahwa ini tidak terjadi exit. Keluar biasanya mengembalikan kontrol ke skrip induk.
Willem Van Onsem

Jawaban:

258

"Masalahnya" sebenarnya adalah Anda mencari dan tidak menjalankan skrip. Saat Anda mencari file, isinya akan dieksekusi di shell saat ini, alih-alih menghasilkan subshell. Jadi semuanya, termasuk keluar, akan mempengaruhi shell saat ini.

Alih-alih menggunakan exit, Anda akan ingin menggunakan return.

Dominik Honnef
sumber
2
Berikut penjelasan lain yang menurut saya bermanfaat: askubuntu.com/a/53179/148337
3cheesewheel
Meskipun benar, ini bukan jawaban yang bagus. Itu mengabaikan bahwa skrip panggilan dapat mendeklarasikan variabel atau fungsi yang disebut skrip perlu akses. Lebih baik menjelaskan bagaimana mengatur kode kembali dan kemudian memprosesnya di runs.sh@ruakh memiliki jawaban yang lebih baik untuk pertanyaan ini.
MikeSchinkel
5
Bagaimana jika fungsinya adalah panggilan bersarang? yaitu panggilan b, b panggilan c, c ingin segera keluar dari a dan b.
Michael
Sumbernya hampir sama dengan copy paste. Lebih baik menggunakan sh <script>atau bash <script>jika seseorang ingin menjalankan skrip dan mengakhiri di beberapa titik
peterchaula
42

Iya; Anda bisa menggunakan returnbukan exit. Tujuan utamanya adalah untuk kembali dari fungsi shell, tetapi jika Anda menggunakannya dalam sourceskrip -d, ia kembali dari skrip itu.

Seperti §4.1 "Bourne Shell Builtins" dari Bash Reference Manual menyatakan:

     return [n]

Menyebabkan fungsi shell untuk keluar dengan nilai pengembalian n . Jika n tidak diberikan, nilai kembali adalah status keluar dari perintah terakhir yang dijalankan dalam fungsi. Ini juga dapat digunakan untuk menghentikan eksekusi skrip yang dieksekusi dengan .(atau source) builtin, mengembalikan n atau status keluar dari perintah terakhir yang dieksekusi dalam skrip sebagai status keluar skrip. Perintah apa pun yang terkait dengan RETURNperangkap dijalankan sebelum eksekusi dilanjutkan setelah fungsi atau skrip. Status pengembalian tidak nol jika returndigunakan di luar fungsi dan tidak selama eksekusi skrip oleh .atau source.

ruakh
sumber
3
returnHANYA dapat digunakan dari suatu fungsi. Jika Anda menggunakan returndan menjalankannya sebagai skrip shell (misalnya sh run.sh), bash akan melaporkan kesalahan - return: can only kembali 'dari suatu fungsi atau skrip bersumber`
Tzunghsing David Wong
@TzungsingDavidWong: Anda sadar bahwa sebagian besar jawaban ini adalah kutipan dari manual referensi resmi? Dan bahwa pesan kesalahan yang Anda kutip setuju dengan jawaban ini alih-alih dengan klaim Anda?
ruakh
Aku tidak setuju denganmu. Saya hanya ingin menunjukkan bahwa returntidak akan berfungsi jika skrip dijalankan sebagai skrip shell dan tidak dijalankan oleh. (atau source). BTW, di mana saya dapat menemukan dokumen tentang source -d?
Tzunghsing David Wong
9

Alih-alih menjalankan skrip menggunakan . run2.sh, Anda dapat menjalankannya menggunakan sh run2.shataubash run2.sh

Sub-shell baru akan dimulai, untuk menjalankan skrip kemudian, itu akan ditutup pada akhir skrip meninggalkan shell lainnya dibuka.

Viorel Mirea
sumber
Jika demikian, lalu mengapa parameter kedua sh "." run2.sh?
CHAN
@ H0WARD Anda benar, saya lupa menghapus titik-titik. Saya sudah mengedit jawabannya sekarang.
Viorel Mirea
1
OP secara eksplisit menyatakan sumber sebagai persyaratan.
Jonathan Neufeld
4

Anda dapat menambahkan perintah keluar tambahan setelah pernyataan kembali / perintah sehingga berfungsi untuk keduanya, menjalankan skrip dari baris perintah dan sumber dari terminal.

Contoh kode keluar dalam skrip:

   if [ $# -lt 2 ]; then
     echo "Needs at least two arguments"
     return 1 2>/dev/null
     exit 1
   fi

Baris dengan exitperintah tidak akan dipanggil ketika Anda sumber skrip setelah returnperintah.

Saat Anda menjalankan skrip, returnperintah memberikan kesalahan. Jadi, kami menekan pesan kesalahan dengan meneruskannya ke /dev/null.

tanpa nama
sumber
3

Sebenarnya, saya pikir Anda mungkin bingung dengan cara Anda shoult run a script.

Jika Anda menggunakan shuntuk menjalankan skrip, katakan sh ./run2.sh,, bahkan jika skrip tertanam diakhiri exit, jendela terminal Anda akan tetap ada.

Namun jika Anda menggunakan .atau source, jendela terminal Anda akan keluar / ditutup juga ketika subskrip berakhir.

untuk detail lebih lanjut, silakan lihat Apa perbedaan antara menggunakan shdan source?

karl li
sumber
2

Ini seperti Anda meletakkan fungsi run di dalam skrip run2.sh. Anda menggunakan kode keluar di dalam menjalankan saat sumber file run2.sh Anda di bash tty. Jika fungsi run memberikan kekuatannya untuk keluar dari skrip Anda dan berikan run2.sh kekuatannya untuk keluar dari terminator. Kemudian karena fungsi jalankan memiliki kekuatan untuk keluar dari teminator Anda.

    #! /bin/sh
    # use . run2.sh

    run()
    {
        echo "this is run"
        #return 0
        exit 0
    }

    echo "this is begin"
    run
    echo "this is end"

Bagaimanapun, saya menyetujui dengan Kaz itu masalah desain.

Umae
sumber
Tidak jelas dari teks apa yang coba dilakukan oleh jawaban ini, tetapi jelas tidak menyelesaikan pertanyaan yang ada.
Luís de Sousa
2

Saya memiliki masalah yang sama dan dari jawaban di atas dan dari apa yang saya pahami apa yang akhirnya berhasil bagi saya adalah:

  1. Memiliki garis shebang yang memanggil skrip yang dimaksud, misalnya,

    #!/bin/bashgunakan bashuntuk mengeksekusi skrip

Saya punya skrip dengan kedua jenis shebang. Karena itu, menggunakan shatau .tidak dapat diandalkan, karena menyebabkan kesalahan eksekusi (seperti ketika skrip bail out telah berjalan tidak lengkap)

Karena itu, jawabannya adalah

    • Pastikan skrip memiliki shebang, sehingga tidak ada keraguan tentang penangan yang dimaksud.
    • chmod file .sh sehingga dapat dieksekusi. (chmod +x file.sh)
    • Meminta secara langsung tanpa shatau.

      (./myscript.sh)

Semoga ini bisa membantu seseorang dengan pertanyaan atau masalah serupa.

gk_2000
sumber
1

Saya pikir ini terjadi karena Anda menjalankannya pada mode sumber dengan titik

. myscript.sh

Anda harus menjalankannya dalam subkulit:

/full/path/to/script/myscript.sh

'sumber' http://ss64.com/bash/source.html

JBoy
sumber
Anda tidak perlu path lengkap ke skrip jika . myscript.shberfungsi. Paling-paling, Anda mungkin perlu ./myscript.sh.
Álvaro González
1

Benar bahwa skrip bersumber vs dieksekusi menggunakan returnvs. exituntuk menjaga sesi yang sama tetap terbuka, seperti yang telah dicatat orang lain.

Berikut tip terkait, jika Anda menginginkan skrip yang membuat sesi tetap terbuka, terlepas dari apakah itu bersumber atau tidak.

Contoh berikut dapat dijalankan secara langsung seperti foo.shatau bersumber seperti . foo.sh/ source foo.sh. Apa pun itu, sesi akan tetap terbuka setelah "keluar". The $@string berlalu begitu bahwa fungsi memiliki akses ke argumen script luar itu.

#!/bin/sh
foo(){
    read -p "Would you like to XYZ? (Y/N): " response;
    [ $response != 'y' ] && return 1;
    echo "XYZ complete (args $@).";
    return 0;
    echo "This line will never execute.";
}
foo "$@";

Hasil terminal:

$ foo.sh
$ Apakah Anda ingin XYZ? (Y / T): n
$. foo.sh
$ Anda ingin ke XYZ? (Y / T): n
$ |
(jendela terminal tetap terbuka dan menerima input tambahan)

Ini dapat berguna untuk dengan cepat menguji perubahan skrip dalam satu terminal sambil menjaga sekelompok kode memo di bawah utama exit/ returnsaat Anda bekerja. Bisa juga membuat kode lebih portabel dalam arti (jika Anda memiliki banyak skrip yang mungkin atau mungkin tidak dipanggil dengan cara yang berbeda), meskipun jauh lebih kikuk untuk digunakan returndan exitjika perlu.

Beejor
sumber
0

jika emulator terminal Anda tidak memiliki, -holdAnda dapat membersihkan skrip bersumber dan menahan terminal dengan:

#!/bin/sh
sed "s/exit/return/g" script >/tmp/script
. /tmp/script
read

jika tidak, Anda dapat menggunakan $TERM -hold -e script

technosaurus
sumber
0

Pastikan juga untuk kembali dengan nilai pengembalian yang diharapkan. Lain jika Anda menggunakan keluar ketika Anda akan menemukan keluar itu akan keluar dari shell dasar Anda karena sumber tidak membuat proses lain (contoh).

coder23
sumber
0

Untuk menulis naskah yang aman untuk dijalankan baik sebagai shell script atau bersumber sebagai file rc, script dapat memeriksa dan membandingkan $0dan $BASH_SOURCEdan menentukan apakah exitdapat digunakan dengan aman.

Berikut ini cuplikan kode singkat untuk itu

[ "X$(basename $0)" = "X$(basename $BASH_SOURCE)" ] && \
    echo "***** executing $name_src as a shell script *****" || \
    echo "..... sourcing $name_src ....."
Tzunghsing David Wong
sumber
-1

1) keluar 0 akan keluar dari skrip jika berhasil.

2) keluar 1 akan keluar dari skrip jika gagal.

Anda dapat mencoba keduanya di atas berdasarkan ur req.

Teja
sumber