ค่า min และ max ของรหัสการออกใน Linux คืออะไร?


40

ค่า min และ max ของรหัสทางออกต่อไปนี้ใน Linux คืออะไร:

  1. โค้ดทางออกที่ส่งคืนจากไบนารีที่เรียกใช้งานได้ (ตัวอย่างเช่น: โปรแกรม C)
  2. รหัสทางออกที่ส่งคืนจากสคริปต์ทุบตี (เมื่อโทรexit)
  3. รหัสทางออกที่ส่งคืนจากฟังก์ชัน (เมื่อโทรreturn) ผมคิดว่านี่เป็นเรื่องระหว่างและ0255

สำหรับตอนที่ 3 คุณหมายถึงการกลับมาจากฟังก์ชั่นเชลล์หรือไม่? ที่อาจขึ้นอยู่กับเชลล์ แต่ฉันทราบว่าคู่มือของ Bash กล่าวว่า " สถานะ Exit อยู่ระหว่าง0และ255 " และ " สถานะ Exit จากเชลล์บิวด์อินและคำสั่งผสมยัง จำกัด อยู่ในช่วงนี้ " returnแน่นอนว่า shell builtin
Toby Speight

ที่เกี่ยวข้อง (มีคำตอบสำหรับคำถามส่วนใหญ่ของคุณ): รหัสทางออกเริ่มต้นเมื่อกระบวนการสิ้นสุดลง
Stéphane Chazelas

@TobySpeight นั่นเป็นข้อ จำกัด ของbashเชลล์ บางหอยอื่น ๆ เช่นzshสามารถกลับค่า 32 exitบิตลงนามเหมือน บางคนชอบrcหรือesสามารถส่งคืนข้อมูลประเภทใดก็ได้ที่พวกเขาสนับสนุน (สเกลาร์หรือรายการ) ดูคำถามและคำตอบที่เชื่อมโยงเพื่อดูรายละเอียด
Stéphane Chazelas

คำตอบ:


74

หมายเลขที่ส่งไปยังการเรียก_exit()/ exit_group()ระบบ (บางครั้งเรียกว่ารหัสออกเพื่อหลีกเลี่ยงความคลุมเครือที่มีสถานะออกซึ่งยังหมายถึงการเข้ารหัสของรหัสทางออกหรือหมายเลขสัญญาณและข้อมูลเพิ่มเติมขึ้นอยู่กับว่ากระบวนการนั้นถูกฆ่าหรือออกตามปกติ ) เป็นชนิดintดังนั้นบนระบบที่เหมือน Unix เช่น Linux โดยทั่วไปจะเป็นจำนวนเต็ม 32 บิตที่มีค่าตั้งแต่ -2147483648 (-2 31 ) ถึง 2147483647 (2 31 -1)

อย่างไรก็ตามในระบบทั้งหมดเมื่อการปกครอง (หรือ subreaper เด็กหรือinitถ้าพ่อแม่เสียชีวิต) ใช้wait(), waitpid(), wait3(), wait4()สายระบบจะดึงมันเพียงต่ำกว่า 8 บิตของมันที่มีอยู่ (ค่า 0-255 (2 8 - 1))

เมื่อใช้waitid()API (หรือตัวจัดการสัญญาณบน SIGCHLD) ในระบบส่วนใหญ่ (และPOSIX ในขณะนี้ต้องมีความชัดเจนมากขึ้นในรุ่นมาตรฐานปี 2559 (ดูส_exit()เปค )) จำนวนเต็มจะพร้อมใช้งาน (ในsi_statusฟิลด์ของโครงสร้างที่ส่งคืน ) นั่นไม่ใช่กรณีบน Linux แต่ถึงแม้ว่าจะตัดทอนหมายเลขไปเป็น 8 บิตด้วยwaitid()API แต่ก็มีแนวโน้มที่จะเปลี่ยนแปลงในอนาคต

โดยทั่วไปคุณต้องการใช้ค่า 0 (โดยทั่วไปหมายถึงความสำเร็จ) ถึง 125 เท่านั้นเนื่องจากเชลล์จำนวนมากใช้ค่าที่สูงกว่า 128 ในการ$?แสดงสถานะทางออกเพื่อเข้ารหัสหมายเลขสัญญาณของกระบวนการที่ถูกฆ่าและ 126 และ 127 สำหรับพิเศษ เงื่อนไข

คุณอาจต้องการใช้ 126 ถึง 255 exit()เพื่อหมายถึงสิ่งเดียวกันกับที่ทำกับเชลล์$?(เช่นเมื่อสคริปต์ทำret=$?; ...; exit "$ret") การใช้ค่าภายนอก 0 -> 255 โดยทั่วไปแล้วไม่มีประโยชน์ โดยทั่วไปคุณจะทำเช่นนั้นก็ต่อเมื่อคุณรู้ว่าผู้ปกครองจะใช้waitid()API บนระบบที่ไม่ตัดทอนและคุณจำเป็นต้องมีช่วงค่า 32 บิต โปรดทราบว่าถ้าคุณทำexit(2048)เช่นนั้นจะถูกมองว่าเป็นความสำเร็จโดยผู้ปกครองโดยใช้wait*()API แบบดั้งเดิม

ข้อมูลเพิ่มเติมได้ที่:

หวังว่าคำถาม & คำตอบควรตอบคำถามอื่น ๆ ของคุณเป็นส่วนใหญ่และชี้แจงว่าสถานะการออกนั้นมีความหมายอย่างไร ฉันจะเพิ่มอีกสองสามสิ่ง:

กระบวนการไม่สามารถยุติได้เว้นแต่ว่าจะมีการฆ่าหรือเรียกการเรียก_exit()/ exit_group()ระบบ เมื่อคุณกลับมาจากmain()ในCระบบ libc จะเรียกการเรียกของระบบนั้นด้วยค่าที่ส่งคืน

ภาษาส่วนใหญ่มีexit()ฟังก์ชั่นที่ล้อมรอบการเรียกของระบบและค่าที่ใช้ถ้าโดยทั่วไปจะถูกส่งผ่านไปยังการเรียกของระบบ (โปรดทราบว่าสิ่งเหล่านั้นมักจะทำสิ่งต่างๆมากกว่าเช่นการล้างข้อมูลด้วยexit()ฟังก์ชั่นของ C ซึ่งจะลบบัฟเฟอร์ stdio, รันatexit()hooks ...

นั่นคือกรณีอย่างน้อย:

$ 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)

คุณเห็นบางครั้งที่บ่นเมื่อคุณใช้ค่านอก 0-255:

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

เชลล์บางตัวบ่นเมื่อคุณใช้ค่าลบ:

$ 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 ออกจากลักษณะการทำงานที่ไม่ได้กำหนดหากค่าที่ส่งผ่านไปยังexitบิวด์อินพิเศษนั้นอยู่นอก 0-> 255

เชลล์บางตัวแสดงพฤติกรรมที่ไม่คาดคิดหากคุณ:

  • bash(และmkshไม่ใช่pdkshที่อิง) ใช้กับตัวเองเพื่อตัดค่าเป็น 8 บิต:

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

    ดังนั้นในเชลล์เหล่านั้นหากคุณต้องการออกด้วยค่านอก 0-255 คุณต้องทำสิ่งต่อไปนี้:

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

    นั่นคือรันคำสั่งอื่นในกระบวนการเดียวกันที่สามารถเรียกการเรียกของระบบด้วยค่าที่คุณต้องการ

  • ดังที่กล่าวไว้ในคำถาม & คำตอบอื่น ๆ ว่าksh93มีพฤติกรรมที่แปลกประหลาดที่สุดสำหรับค่าออกจาก 257 ถึง 256 + max_signal_number ซึ่งแทนที่จะเรียกexit_group()มันจะฆ่าตัวเองด้วยสัญญาณที่สอดคล้องกัน¹

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

    และอื่น ๆ ตัดทอนจำนวนเช่น/bashmksh


¹มีแนวโน้มว่าจะเปลี่ยนแปลงในรุ่นถัดไป ขณะนี้การพัฒนาksh93ได้ถูกยึดเป็นความพยายามของชุมชนนอก AT&T พฤติกรรมดังกล่าวแม้ว่า POSIX จะได้รับการสนับสนุน แต่อย่างใด


2
คุณรู้หรือไม่ว่ามีการพูดคุยกันเรื่องการนำรหัสออกเต็มรูปแบบมาใช้กับsi_statusLinux?
Ruslan

2
@Ruslan ไม่เกินaustingroupbugs.net/view.php?id=594#c1318 (จาก Eric Blake (RedHat)) ที่ลิงก์ที่ฉันให้
Stéphane Chazelas

1
"เป็นชนิด int ดังนั้นจำนวนเต็ม 32 บิต" ลินุกซ์รับประกันว่า int จะเป็น 32 บิตเสมอหรือไม่ แม้แต่ตอนที่ทำงานกับไมโครคอนโทรลเลอร์ขนาดเล็กเหล่านั้นบางตัว? นั่นทำให้ฉันแปลกอย่างมาก POSIX ไม่แน่นอน
Voo

@Voo ไมโครคอนโทรลเลอร์ขนาดเล็กเหล่านั้นไม่สามารถเรียกใช้ Linux ได้ ในขณะที่ซีต้องintเป็นอย่างน้อย 16 บิต, POSIX มากหรือน้อยต้องให้มันเป็นอย่างน้อย 32 บิตและการเขียนโปรแกรมที่จะมีสภาพแวดล้อมที่ uint32_t ฉันไม่ทราบว่า Linux สนับสนุนสภาพแวดล้อมการเขียนโปรแกรมใด ๆ ที่ ints เป็นอะไรนอกจาก 32 บิตฉันไม่เคยเจอเลย
Stéphane Chazelas

1
บน POSIX comliant OS คุณอาจได้รับรหัสทางออก 32 บิตเต็มรูปแบบในเวอร์ชันล่าสุดของ Bourne Shell โปรดดู: schillix.sourceforge.net/man/man1/bosh.1.html
schily

12

ขั้นต่ำคือ0และถือว่าเป็นค่าความสำเร็จ สิ่งอื่น ๆ ทั้งหมดนั้นล้มเหลว สูงสุดที่เป็นที่รู้จักกันว่า255-1

กฎเหล่านี้ใช้กับทั้งสคริปต์และไฟล์ปฏิบัติการอื่น ๆ รวมถึงฟังก์ชั่นเชลล์

ค่าที่ใหญ่กว่าส่งผลให้ modulo 256


2
เพื่อความแม่นยำในเชลล์คล้ายบอร์นบางตัว (แต่ไม่ใช่bashหรือที่ใช้กันมากที่สุด) รหัสทางออกที่ส่งผ่านไปยังบิวอินexitจะไม่ถือว่าเป็น modulo-256 และทำให้เกิดข้อผิดพลาดแทน (ตัวอย่างเช่นการใช้งานร่วมกันexit -1นั้นไม่ใช่แบบพกพาเทียบเท่ากับexit 255ในเชลล์ส่วนใหญ่) และไม่ว่าจะexit(-1)อยู่ในระดับ C เทียบเท่ากับexit(255)รายละเอียดที่เป็นจริงในการทำงานหรือไม่ แต่ขึ้นอยู่กับพฤติกรรมการใช้งานที่กำหนดไว้ (แม้ว่านี่จะไม่เป็นปัญหาสำหรับระบบสมัยใหม่ที่คุณน่าจะใช้ในทางปฏิบัติ)
mtraceur

จากสิ่งที่ฉันรู้เพียง ksh93 จำกัดexit(1)พารามิเตอร์ไว้ที่ 8 บิต
schily

6

มันดูเรียบง่ายมาก แต่ก็ไม่เป็นไร

ภาษา C (และตามด้วยภาษาอื่น ๆ ส่วนใหญ่ไม่ว่าทางตรงหรือทางอ้อม) กำหนดให้การส่งคืนmainนั้นเทียบเท่ากับการโทรexitด้วยอาร์กิวเมนต์เดียวกันกับค่าส่งคืน นี้เป็นจำนวนเต็ม (ประเภทกลับเป็นอย่างมากอย่างเห็นได้ชัดint) ดังนั้นในหลักการช่วงจะไปINT_MININT_MAX

อย่างไรก็ตามรัฐ POSIXว่ามีเพียงน้อยที่สุด 8 บิตส่งผ่านไปยังexitต้องมีไว้เพื่อเป็นกระบวนการที่ผู้ปกครองรอแท้จริงราวกับว่ามันเป็น"สถานะและ 0xFF"
ดังนั้นในทางปฏิบัติรหัสออกจะเป็นจำนวนเต็ม (ยังเซ็นชื่อ) ซึ่งมีเพียง 8 บิตต่ำสุดเท่านั้น

ขั้นต่ำจึงจะ -128 และสูงสุดที่ 127 แขวนอยู่นั่นไม่ใช่ความจริง มันจะเป็น 0 ถึง 255

แต่แน่นอนว่ามันไม่ง่ายอย่างนั้น ในทางปฏิบัติลินุกซ์ (หรือมากกว่าทุบตี) ไม่มันแตกต่างกัน ช่วงของรหัสส่งคืนที่ถูกต้องคือ 0 ถึง 255 (เช่นไม่ได้ลงนาม)

การที่จะอยู่อย่างปลอดภัยในแง่ของการหลีกเลี่ยงความสับสนอาจเป็นความคิดที่ดีที่จะสมมติว่ารหัสส่งคืนนั้นไม่มีwaitการลงนาม วิธีนี้สอดคล้องกับสิ่งที่คุณเห็นในเปลือก เนื่องจากบิตที่อยู่ด้านบนสุด (รวมถึงที่สำคัญที่สุด) ถูกล้างออกนั่นไม่ใช่แม้แต่ "ผิด" เพราะถึงแม้ว่าลงชื่อทางเทคนิคแล้วค่าที่แท้จริงจะไม่ได้รับการลงนามเสมอ
นอกจากนี้ยังช่วยหลีกเลี่ยงข้อผิดพลาดทั่วไปของการเปรียบเทียบรหัสการออก-1ด้วยซึ่งด้วยเหตุผลแปลก ๆ บางอย่างก็ไม่ปรากฏขึ้นแม้ในขณะที่โปรแกรมออกด้วย-1(ดีเดาว่าทำไม!)

เกี่ยวกับจุดสุดท้ายของคุณกลับมาจากฟังก์ชั่นถ้าฟังก์ชั่นนี้เกิดขึ้นmainแล้วดูด้านบน มิฉะนั้นจะขึ้นอยู่กับประเภทการคืนของฟังก์ชั่นโดยหลักการแล้วมันอาจเป็นอะไรก็ได้ (รวมถึงvoid)


คุณได้รับสิทธิก่อนปี 1989 เมื่อwaitid()มีการเปิดตัว
schily

@schily: ไม่แน่ใจว่าคุณหมายถึงอะไร? waitid()ทำในสิ่งเดียวกันแตกต่างกันเล็กน้อย มันรอให้รหัสเฉพาะหรือหัวข้อใด ๆ และมันจะเขียนผลการชี้ไปยังsiginfo_tโครงสร้างที่si_statusเป็นint(ดังนั้น ... ลงนามเพียงแค่เดียวกัน) ถึงกระนั้นexit()เพียงแค่ผ่านบิตต่ำสุด 8 บิตดังนั้น ... สิ่งเดียวกันภายใต้ประทุน
Damon

exit()ส่งผ่านพารามิเตอร์ 32 บิตทั้งหมดไปยังเคอร์เนลและwaitid()ส่งคืน 32 บิตทั้งหมดจากรหัสออก บางทีคุณตรวจสอบบน Linux ที่ไม่มีใครใส่ใจแก้ไขข้อบกพร่อง ถ้าคุณไม่เชื่อฉันตรวจสอบบน POSIX complient ... OS
schily

@schily: หากที่เป็นจริง (ผมไม่คิดว่ามันเป็น แต่ต่อไป) แล้วลินุกซ์เสีย โปรดอ่านข้อกำหนด POSIX ที่เชื่อมโยงไปยังคำตอบของexitโดยเฉพาะอย่างยิ่งบรรทัดที่สองภายใต้ "คำอธิบาย" ซึ่งระบุว่า: "แม้ว่าจะมีบิตที่มีนัยสำคัญเพียง 8 บิตเท่านั้น (นั่นคือสถานะ & 0377) เท่านั้น " . นั่นคือการใช้งานที่สอดคล้องกัน - ต่ำสุด 8 บิตไม่ใช่ 32. คุณมีการอ้างอิงสำหรับ 32 บิตที่ถูกส่งต่อไปหรือไม่?
เดมอน

ฉันคิดว่าฉันพูดถึงว่า Linux เสีย ยิ่งไปกว่านั้น: คนเคอร์เนล Linux ปฏิเสธที่จะแก้ไขข้อบกพร่อง หากคุณอ่านมาตรฐาน POSIX คุณจะพบว่ารุ่น 1995 (SUSv1) ได้อธิบายคุณสมบัติที่ SVR4 นำมาใช้ในปี 1989 และรุ่นล่าสุด (เช่น SUSv7tc2) ของมาตรฐานได้อธิบายอย่างชัดเจนwaitid()และโครงสร้างที่siginfo_tส่งผ่านไปยังSIGCHLDตัวจัดการกลับ ทั้งหมด 32 บิตจากexit()พารามิเตอร์
schily

2
  1. โค้ดทางออกที่ส่งคืนจากไบนารีที่เรียกใช้งานได้ (ตัวอย่างเช่น: โปรแกรม C)
  2. รหัสทางออกที่ส่งคืนมาจากสคริปต์ทุบตี (เมื่อเรียกทางออก)

รหัสการออกจากกระบวนการใด ๆ - ไม่ว่าจะเป็นไบนารีที่ปฏิบัติการได้, เชลล์สคริปต์หรือสิ่งอื่นใด - อยู่ในช่วงตั้งแต่ 0 ถึง 255 มันเป็นไปได้ที่จะส่งค่าที่มากขึ้นให้exit()แต่สถานะ 8 บิตที่ต่ำกว่าเท่านั้น กระบวนการอื่น ๆ wait()ผ่าน

  1. รหัสทางออกที่ส่งคืนจากฟังก์ชั่น (เมื่อโทรกลับ) ฉันคิดว่านี่คือระหว่าง 0 และ 255

ฟังก์ชั่น AC สามารถประกาศเป็นการส่งคืนเกือบทุกประเภท ขีด จำกัด ของค่าตอบแทนของมันจะถูกกำหนดโดยสิ้นเชิงประเภทที่: ยกตัวอย่างเช่น -128 ถึง 127 สำหรับฟังก์ชั่นที่กลับมาsigned charหรือ 0-4200000000 สำหรับฟังก์ชั่นที่กลับมาunsigned intหรือใด ๆ จำนวนจุดลอยตัวและรวมถึงสำหรับฟังก์ชั่นกลับมาinf doubleและนั่นไม่นับประเภทที่ไม่ใช่ตัวเลขเช่นvoid *หรือstruct...

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.