Berapa nilai minimum dan maksimum dari kode keluar di Linux?


40

Berapakah nilai min dan maks dari kode keluar berikut di Linux:

  1. Kode keluar kembali dari biner yang dapat dieksekusi (misalnya: program C).
  2. Kode keluar kembali dari skrip bash (saat memanggil exit).
  3. Kode keluar kembali dari fungsi (saat memanggil return). Saya pikir ini antara 0dan 255.

Untuk bagian 3, maksud Anda kembali dari fungsi shell ? Itu mungkin tergantung pada shell, tetapi saya perhatikan bahwa manual Bash mengatakan " Status keluar jatuh antara 0 dan 255 " dan " Status keluar dari shell builtin dan perintah majemuk juga terbatas pada kisaran ini. " return, Tentu saja, shell builtin.
Toby Speight

Terkait (memiliki jawaban atas sebagian besar pertanyaan Anda): Kode keluar default saat proses dihentikan?
Stéphane Chazelas

@ TorySpeight, itu adalah batasan dari bashshell. Beberapa shell lain seperti zshdapat mengembalikan nilai 32 bit apa pun yang ditandatangani seperti untuk exit. Beberapa suka rcatau esdapat mengembalikan data dari salah satu jenis yang mereka dukung (skalar atau daftar). Lihat tanya jawab terkait untuk perincian.
Stéphane Chazelas

Jawaban:


74

Nomor yang diteruskan ke sistem _exit()/ exit_group()panggilan (kadang-kadang disebut sebagai kode keluar untuk menghindari ambiguitas dengan status keluar yang juga mengacu pada penyandian kode keluar atau nomor sinyal dan info tambahan tergantung pada apakah proses itu dibunuh atau keluar secara normal ) bertipe int, jadi pada sistem mirip Unix seperti Linux, biasanya integer 32bit dengan nilai dari -2147483648 (-2 31 ) hingga 2147483647 (2 31 -1).

Namun, pada semua sistem, ketika proses induk (atau subreaper anak atau initjika orang tua meninggal) menggunakan wait(), waitpid(), wait3(), wait4()panggilan sistem untuk mengambilnya, hanya 8 bit rendah dari itu tersedia (nilai 0 sampai 255 (2 8 - 1)).

Saat menggunakan waitid()API (atau penangan sinyal di SIGCHLD), pada sebagian besar sistem (dan seperti POSIX sekarang lebih jelas mensyaratkan dalam edisi standar 2016 (lihat _exit()spesifikasi )), angka lengkap tersedia (di si_statusbidang struktur yang dikembalikan ). Namun itu tidak terjadi di Linux yang juga memotong angka menjadi 8 bit dengan waitid()API, meskipun itu kemungkinan akan berubah di masa depan.

Secara umum, Anda hanya ingin menggunakan nilai 0 (umumnya berarti sukses) menjadi 125 saja, karena banyak shell menggunakan nilai di atas 128 dalam $?representasi mereka dari status keluar untuk menyandikan nomor sinyal dari suatu proses yang terbunuh dan 126 dan 127 untuk khusus kondisi.

Anda mungkin ingin menggunakan 126 hingga 255 exit()untuk mengartikan hal yang sama seperti yang mereka lakukan untuk shell $?(seperti ketika skrip melakukannya ret=$?; ...; exit "$ret"). Menggunakan nilai di luar 0 -> 255 umumnya tidak berguna. Anda biasanya hanya akan melakukannya jika Anda tahu orang tua akan menggunakan waitid()API pada sistem yang tidak terpotong dan Anda memiliki kebutuhan untuk rentang nilai 32-bit. Perhatikan bahwa jika Anda melakukan exit(2048)misalnya, itu akan dilihat sebagai keberhasilan oleh orang tua menggunakan wait*()API tradisional .

Info lebih lanjut di:

T&J tersebut semoga dapat menjawab sebagian besar pertanyaan Anda yang lain dan mengklarifikasi apa yang dimaksud dengan status keluar . Saya akan menambahkan beberapa hal lagi:

Suatu proses tidak dapat berakhir kecuali itu dimatikan atau memanggil sistem _exit()/ exit_group()panggilan. Ketika Anda kembali dari main()dalam C, libc memanggil sistem itu memanggil dengan nilai kembali.

Sebagian besar bahasa memiliki exit()fungsi yang membungkus panggilan sistem itu, dan nilai yang diambilnya, jika ada yang umumnya dilewatkan seperti halnya panggilan sistem. (perhatikan bahwa mereka umumnya melakukan lebih banyak hal seperti pembersihan yang dilakukan oleh exit()fungsi C yang membersihkan buffer stdio, menjalankan atexit()kait ...)

Setidaknya itulah yang terjadi:

$ strace -e exit_group awk 'BEGIN{exit(1234)}'
exit_group(1234)                        = ?
$ strace -e exit_group mawk 'BEGIN{exit(1234)}'
exit_group(1234)                        = ?
$ strace -e exit_group busybox awk 'BEGIN{exit(1234)}'
exit_group(1234)                        = ?
$ echo | strace -e exit_group sed 'Q1234'
exit_group(1234)                        = ?
$ strace -e exit_group perl -e 'exit(1234)'
exit_group(1234)                        = ?
$ strace -e exit_group python -c 'exit(1234)'
exit_group(1234)                        = ?
$ strace -e exit_group expect -c 'exit 1234'
exit_group(1234)                        = ?
$ strace -e exit_group php -r 'exit(1234);'
exit_group(1234)                        = ?
$ strace -e exit_group zsh -c 'exit 1234'
exit_group(1234)

Anda sesekali melihat beberapa yang mengeluh ketika Anda menggunakan nilai di luar 0-255:

$ echo 'm4exit(1234)' | strace -e exit_group m4
m4:stdin:1: exit status out of range: `1234'
exit_group(1)                           = ?

Beberapa shell mengeluh ketika Anda menggunakan nilai negatif:

$ strace -e exit_group dash -c 'exit -1234'
dash: 1: exit: Illegal number: -1234
exit_group(2)                           = ?
$ strace -e exit_group yash -c 'exit -- -1234'
exit: `-1234' is not a valid integer
exit_group(2)                           = ?

POSIX membiarkan perilaku tidak terdefinisi jika nilai yang diteruskan ke exitbuiltin khusus berada di luar 0-> 255.

Beberapa kerang menunjukkan beberapa perilaku tak terduga jika Anda melakukannya:

  • bash(dan mkshtetapi tidak pdkshberdasarkan yang mana) mengambil sendiri untuk memotong nilai menjadi 8 bit:

    $ strace -e exit_group bash -c 'exit 1234'
    exit_group(210)                         = ?
    

    Jadi di shell itu, jika Anda ingin keluar dengan nilai di luar 0-255, Anda harus melakukan sesuatu seperti:

    exec zsh -c 'exit -- -12345'
    exec perl -e 'exit(-12345)'
    

    Yaitu menjalankan perintah lain dalam proses yang sama yang dapat memanggil system call dengan nilai yang Anda inginkan.

  • seperti yang disebutkan pada T&J lainnya, ksh93memiliki perilaku paling aneh untuk nilai keluar dari 257 hingga 256 + max_signal_number di mana alih-alih memanggil exit_group(), ia membunuh dirinya sendiri dengan sinyal yang sesuai¹.

    $ ksh -c 'exit "$((256 + $(kill -l STOP)))"'
    zsh: suspended (signal)  ksh -c 'exit "$((256 + $(kill -l STOP)))"'
    

    dan sebaliknya memotong angka seperti bash/ mksh.


¹ Namun itu kemungkinan akan berubah di versi berikutnya. Sekarang pengembangan ksh93telah diambil alih sebagai upaya komunitas di luar AT&T, perilaku itu, meskipun didorong oleh POSIX, sedang dipulihkan


2
Apakah Anda tahu jika ada diskusi tentang penerapan kode keluar lengkap si_statusuntuk Linux?
Ruslan

2
@Ruslan, tidak lebih dari austingroupbugs.net/view.php?id=594#c1318 (dari Eric Blake (RedHat)) di tautan yang saya berikan
Stéphane Chazelas

1
msgstr "adalah tipe int, jadi integer 32bit". Linux benar-benar menjamin bahwa sebuah int akan selalu 32bit? Bahkan ketika berjalan di beberapa mikrokontroler kecil itu? Itu menurut saya sangat aneh. POSIX tentu saja tidak.
Voo

@ Oh, mikrokontroler kecil itu tidak bisa menjalankan Linux. Sementara C membutuhkan intsetidaknya 16 bit, POSIX lebih atau kurang mengharuskannya menjadi setidaknya 32 bit dan lingkungan pemrograman untuk memiliki uint32_t . Saya tidak tahu apakah Linux mendukung lingkungan pemrograman mana pun kecuali intinya, tetapi saya tidak pernah menemukan itu.
Stéphane Chazelas

1
Pada OS yang sesuai dengan POSIX, Anda bisa mendapatkan kode keluar 32 bit penuh dalam versi terbaru dari Bourne Shell, lihat: schillix.sourceforge.net/man/man1/bosh.1.html
schily

12

Minimal 0, dan itu dianggap sebagai nilai keberhasilan. Semua yang lain adalah kegagalan. Maksimum 255juga dikenal sebagai -1.

Aturan ini berlaku untuk skrip dan file executable lainnya, serta fungsi shell.

Nilai yang lebih besar menghasilkan modulo 256.


2
Tepatnya, dalam beberapa shell seperti Bourne (tetapi tidak bashatau yang paling umum digunakan) kode keluar yang diteruskan ke exitbuiltin tidak diperlakukan sebagai modulo-256, dan malah menyebabkan kesalahan. (Misalnya, common exit -1sebenarnya tidak setara dengan portable exit 255di kebanyakan shell). Dan apakah exit(-1)pada level C setara dengan exit(255)detail yang pasti bekerja, tetapi bergantung pada implementasi perilaku yang ditentukan (meskipun ini bukan masalah pada sistem modern yang mungkin Anda gunakan dalam praktiknya).
mtraceur

Dari yang saya tahu, hanya ksh93 yang membatasi exit(1)parameter hingga 8 bit.
schily

6

Ini terlihat sangat sederhana, tetapi oh kesengsaraan.

Bahasa C (dan mengikuti sebagian besar bahasa lain secara langsung atau tidak langsung) mensyaratkan bahwa pengembalian dari mainsetara dengan panggilan exitdengan argumen yang sama dengan nilai pengembalian. Ini adalah bilangan bulat (jenis kembali sangat jelas int), sehingga pada prinsipnya kisaran akan INT_MINuntuk INT_MAX.

Namun, POSIX menyatakan bahwa hanya 8 bit paling rendah yang dilewatkan exitharus disediakan untuk proses induk menunggu, secara harfiah seolah-olah itu "status & 0xFF" .
Jadi, dalam praktiknya, kode keluar adalah integer (masih ditandatangani) yang hanya menetapkan 8 bit terendah.

Minimum akan menjadi -128, dan maksimum 127 . Tunggu dulu, itu tidak benar. Itu akan menjadi 0 hingga 255.

Namun sayang, tentu saja tidak sesederhana itu . Dalam praktiknya, Linux (atau lebih tepatnya bash) melakukannya secara berbeda . Rentang kode pengembalian yang valid adalah 0 hingga 255 (yaitu tidak ditandatangani).

Untuk berada di sisi yang aman dalam hal menghindari kebingungan, mungkin ide yang baik untuk mengasumsikan bahwa kode pengembalian tidak ditandatangani, dan membuang apa pun yang Anda dapatkan dari waitmenjadi tidak ditandatangani. Dengan cara itu konsisten dengan apa yang Anda lihat di shell. Karena bit paling atas (termasuk yang paling signifikan) dihapus, itu bahkan tidak "salah" karena meskipun secara teknis ditandatangani, nilai aktual selalu tidak ditandatangani (karena bit tanda tidak pernah disetel).
Ini juga membantu menghindari kesalahan umum membandingkan kode keluar -1, yang untuk beberapa alasan aneh sepertinya tidak pernah muncul bahkan ketika sebuah program keluar dengan -1(yah, tebak kenapa!).

Tentang poin terakhir Anda, kembali dari suatu fungsi, jika fungsi ini kebetulan main, maka lihat di atas. Kalau tidak, itu tergantung pada apa jenis kembali fungsi itu, pada prinsipnya bisa apa saja (termasuk void)


Anda benar sebelum 1989 ketika waitid()diperkenalkan.
schily

@ Schily: Tidak yakin apa yang Anda maksud? waitid()melakukan hal yang sama, sedikit berbeda. Ini menunggu untuk id tertentu atau benang pun, dan menulis hasil ke menunjuk ke siginfo_tstruktur di mana si_statusadalah int(jadi ... ditandatangani , sama saja). Namun, exit()hanya melewati 8 bit paling bawah, jadi ... benar-benar hal yang sama di bawah tenda.
Damon

exit()meneruskan semua 32 bit parameter ke kernel dan waitid()mengembalikan semua 32 bit dari kode keluar. Mungkin Anda memeriksa di Linux di mana tidak ada yang peduli untuk memperbaiki bug. Jika Anda tidak mempercayai saya, periksa pada OS yang sesuai dengan POSIX ...
schily

@ Schily: Jika itu benar (saya rasa itu tidak benar, tapi bagaimanapun juga), maka Linux rusak . Harap baca spesifikasi POSIX tertaut ke jawaban exit, khususnya baris kedua di bawah "Deskripsi" yang menyatakan: "meskipun hanya 8 bit yang paling tidak signifikan (yaitu, status & 0377) harus tersedia untuk proses induk menunggu " . Begitulah implementasi implementasi yang sesuai - 8 bit paling bawah, bukan 32. Apakah Anda memiliki referensi untuk 32 bit yang diteruskan?
Damon

Saya pikir saya menyebutkan bahwa Linux rusak. Lebih buruk lagi: orang-orang kernel Linux menolak untuk memperbaiki bug. Jika Anda membaca standar POSIX, Anda akan menemukan bahwa versi 1995 (SUSv1) dengan benar menjelaskan fitur yang awalnya diperkenalkan oleh SVr4 pada tahun 1989 dan bahwa versi terbaru (misalnya SUSv7tc2) dari standar tersebut bahkan secara eksplisit menjelaskan hal itu waitid()dan siginfo_tstruktur yang diteruskan ke pengembalian SIGCHLDhandler. semua 32 bit dari exit()parameter.
schily

2
  1. Kode keluar kembali dari biner yang dapat dieksekusi (misalnya: program C).
  2. Kode keluar kembali dari skrip bash (saat memanggil keluar).

Keluar dari proses apa pun - apakah itu biner yang dapat dieksekusi, skrip shell, atau apa pun - berkisar dari 0 hingga 255. Mungkin saja untuk memberikan nilai yang lebih besar exit(), tetapi hanya 8 bit yang lebih rendah dari status yang tersedia untuk proses lain melalui wait().

  1. Kode keluar kembali dari suatu fungsi (saat memanggil kembali). Saya pikir ini antara 0 dan 255.

Fungsi AC dapat dinyatakan sebagai mengembalikan hampir semua jenis. Batas nilai kembaliannya ditentukan sepenuhnya oleh tipe itu: misalnya, -128 hingga 127 untuk fungsi yang kembali signed char, atau 0 hingga 4,2 miliar untuk fungsi yang kembali unsigned int, atau angka floating-point hingga dan termasuk infuntuk fungsi yang kembali double. Dan itu tidak termasuk tipe non-numerik, seperti void *atau struct...

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.