รหัสการออกเริ่มต้นเมื่อกระบวนการยุติลง?


54

เมื่อกระบวนการถูกฆ่าด้วยสัญญาณที่จับได้เช่นSIGINTหรือSIGTERMแต่ไม่จัดการสัญญาณสิ่งที่จะเป็นรหัสทางออกของกระบวนการ?

สิ่งที่เกี่ยวกับสัญญาณที่SIGKILLไม่สามารถจัดการได้เป็นอย่างไร

จากสิ่งที่ผมสามารถบอกได้ฆ่ากระบวนการที่มีSIGINTผลแนวโน้มในรหัสทางออก130แต่ที่แตกต่างกันโดย kernel หรือการดำเนินเปลือก?

$ cat myScript
#!/bin/bash
sleep 5
$ ./myScript
<ctrl-c here>
$ echo $?
130

ฉันไม่แน่ใจว่าฉันจะทดสอบสัญญาณอื่น ๆ ได้อย่างไร ...

$ ./myScript &
$ killall myScript
$ echo $?
0  # duh, that's the exit code of killall
$ killall -9 myScript
$ echo $?
0  # same problem

1
killall myScriptผลงานของคุณดังนั้นการกลับมาของ killall (และไม่ใช่สคริปต์!) คือ 0 คุณสามารถวางkill -x $$[x เป็นหมายเลขสัญญาณและ $$ มักจะขยายโดยเชลล์ไปยัง PID ของสคริปต์นั้น (ทำงานเป็น sh, bash, ... )] ภายในสคริปต์แล้วทดสอบว่าอะไรคือแก่นทางออกของมัน
Olivier Dulac


ความคิดเห็นเกี่ยวกับคำถามกึ่ง: อย่าใส่ myScript ในพื้นหลัง (ละเว้น&) ส่งสัญญาณจากกระบวนการเชลล์อื่น (ในเทอร์มินัลอื่น) จากนั้นคุณสามารถใช้$?หลังจาก myScript สิ้นสุดลงแล้ว
MattBianco

คำตอบ:


61

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

โดยทั่วไปผู้ปกครองจะทำwait()หรือwaitpid()รับสถานะลูกของตนเป็นจำนวนเต็ม (แม้ว่าจะwaitid()มีความหมายที่แตกต่างกันบ้างก็สามารถใช้ได้เช่นกัน)

บน Linux และ Unices ที่สุดถ้ากระบวนการยกเลิกโดยปกติบิต 8-15 ที่สถานะexit()จำนวนจะมีรหัสที่ออกเป็นส่งผ่านไปยัง ถ้าไม่เช่นนั้นบิตที่มีนัยสำคัญน้อยที่สุด 7 (0 ถึง 6) จะมีหมายเลขสัญญาณและบิต 7 จะถูกตั้งค่าหากแกนถูกทิ้ง

perl's $?เช่นมีตัวเลขที่ที่กำหนดโดยwaitpid():

$ perl -e 'system q(kill $$); printf "%04x\n", $?'
000f # killed by signal 15
$ perl -e 'system q(kill -ILL $$); printf "%04x\n", $?'
0084 # killed by signal 4 and core dumped
$ perl -e 'system q(exit $((0xabc))); printf "%04x\n", $?'
bc00 # terminated normally, 0xbc the lowest 8 bits of the status

เชลล์ที่มีลักษณะคล้ายบอร์นยังสร้างสถานะการออกของคำสั่ง run ล่าสุดใน$?ตัวแปรของตนเอง อย่างไรก็ตามมันไม่ได้มีหมายเลขที่ส่งคืนโดยตรงโดยตรงwaitpid()แต่เป็นการแปลงที่มันและมันแตกต่างกันระหว่างเปลือกหอย

สิ่งที่พบได้ทั่วไประหว่างเชลล์ทั้งหมดคือที่$?มีบิต 8 บิตต่ำสุดของรหัสออก (จำนวนที่ส่งให้exit()) หากกระบวนการยุติลงตามปกติ

ตำแหน่งที่แตกต่างคือเมื่อกระบวนการถูกยกเลิกโดยสัญญาณ ในทุกกรณีและเป็นสิ่งที่ POSIX ต้องการจำนวนจะมากกว่า 128 POSIX ไม่ได้ระบุค่าที่อาจเป็น ในทางปฏิบัติแม้ว่าในทุกเชลล์ที่มี Bourne เหมือนที่ฉันรู้จักบิตต่ำสุด 7 บิต$?จะมีหมายเลขสัญญาณ แต่nหมายเลขสัญญาณอยู่ที่ไหน

  • ในเถ้า zsh, pdksh, ทุบตีบอร์นเปลือกเป็น$? 128 + nสิ่งที่หมายถึงที่อยู่ในเปลือกหอยเหล่านั้นถ้าคุณได้รับ$?ของ129คุณไม่ทราบว่ามันเป็นเพราะกระบวนการออกด้วยexit(129)หรือไม่ว่าจะถูกฆ่าตายโดยสัญญาณ1( HUPในระบบส่วนใหญ่) แต่เหตุผลคือเชลล์นั้นเมื่อพวกเขาออกจากตัวเองโดยค่าเริ่มต้นกลับสถานะทางออกของคำสั่งที่ออกล่าสุด ด้วยการทำให้แน่ใจว่า$?จะไม่เกิน 255 ซึ่งจะช่วยให้มีสถานะทางออกที่สอดคล้องกัน:

    $ bash -c 'sh -c "kill \$\$"; printf "%x\n" "$?"'
    bash: line 1: 16720 Terminated              sh -c "kill \$\$"
    8f # 128 + 15
    $ bash -c 'sh -c "kill \$\$"; exit'; printf '%x\n' "$?"
    bash: line 1: 16726 Terminated              sh -c "kill \$\$"
    8f # here that 0x8f is from a exit(143) done by bash. Though it's
       # not from a killed process, that does tell us that probably
       # something was killed by a SIGTERM
    
  • ksh93, เป็น$? 256 + nนั่นหมายความว่าจากคุณค่าของ$?คุณสามารถแยกความแตกต่างระหว่างกระบวนการที่ถูกฆ่าและไม่ถูกฆ่า เวอร์ชันที่ใหม่กว่าของkshถ้าออก$?มากกว่า 255 ฆ่าตัวเองด้วยสัญญาณเดียวกันเพื่อที่จะสามารถรายงานสถานะการออกเดียวกันกับผู้ปกครอง ในขณะที่ฟังดูเป็นความคิดที่ดีหมายความว่าkshจะสร้างการถ่ายโอนข้อมูลหลักพิเศษ (อาจเขียนทับอีกรายการหนึ่ง) หากกระบวนการถูกฆ่าโดยสัญญาณสร้างแกน:

    $ ksh -c 'sh -c "kill \$\$"; printf "%x\n" "$?"'
    ksh: 16828: Terminated
    10f # 256 + 15
    $ ksh -c 'sh -c "kill -ILL \$\$"; exit'; printf '%x\n' "$?"
    ksh: 16816: Illegal instruction(coredump)
    Illegal instruction(coredump)
    104 # 256 + 15, ksh did indeed kill itself so as to report the same
        # exit status as sh. Older versions of `ksh93` would have returned
        # 4 instead.
    

    ที่คุณสามารถพูดได้ว่ามีข้อผิดพลาดคือksh93ฆ่าตัวเองแม้ว่าจะ$?มาจากreturn 257ฟังก์ชั่นที่ทำโดย:

    $ ksh -c 'f() { return "$1"; }; f 257; exit'
    zsh: hangup     ksh -c 'f() { return "$1"; }; f 257; exit'
    # ksh kills itself with a SIGHUP so as to report a 257 exit status
    # to its parent
    
  • yash. yashเสนอการประนีประนอม มันกลับ256 + 128 + nมา นั่นหมายความว่าเราสามารถแยกความแตกต่างระหว่างกระบวนการที่ถูกฆ่าและกระบวนการที่ถูกยกเลิกได้อย่างถูกต้อง และเมื่อออกมามันจะรายงาน128 + nโดยไม่ต้องฆ่าตัวตายและผลข้างเคียงที่มันสามารถมีได้

    $ yash -c 'sh -c "kill \$\$"; printf "%x\n" "$?"'
    18f # 256 + 128 + 15
    $ yash -c 'sh -c "kill \$\$"; exit'; printf '%x\n' "$?"
    8f  # that's from a exit(143), yash was not killed
    

เพื่อรับสัญญาณจากค่าของ$?วิธีการพกพาคือการใช้kill -l:

$ /bin/kill 0
Terminated
$ kill -l "$?"
TERM

(สำหรับการพกพาคุณไม่ควรใช้หมายเลขสัญญาณเพียงชื่อสัญญาณเท่านั้น)

บนแนวรบที่ไม่ใช่บอร์น:

  • csh/ tcshและfishเหมือนกับเชลล์เป้าหมายยกเว้นว่าสถานะนั้นอยู่ในสถานะ$statusแทนที่จะเป็น$?(โปรดทราบว่าzshยังตั้งค่า$statusความเข้ากันได้กับcsh(นอกเหนือจาก$?))
  • rc: สถานะทางออกอยู่$statusเช่นกัน แต่เมื่อถูกฆ่าโดยสัญญาณตัวแปรนั้นจะมีชื่อของสัญญาณ (เช่นsigtermหรือsigill+coreหากแกนถูกสร้างขึ้น) แทนที่จะเป็นตัวเลขซึ่งเป็นหลักฐานการออกแบบเชลล์ที่ดีอีกตัวหนึ่ง .
  • es. สถานะการออกไม่ใช่ตัวแปร หากคุณสนใจคุณเรียกใช้คำสั่งเป็น:

    status = <={cmd}
    

    ซึ่งจะกลับจำนวนหรือsigtermหรือชอบในsigsegv+corerc

อาจจะเพื่อความสมบูรณ์เราควรจะพูดถึงzsh's $pipestatusและbash' s $PIPESTATUSอาร์เรย์ที่มีสถานะออกจากส่วนประกอบของท่อที่ผ่านมา

และเพื่อความสมบูรณ์เมื่อพูดถึงฟังก์ชั่นเชลล์และไฟล์ที่มาโดยฟังก์ชั่นเริ่มต้นกลับมาพร้อมกับสถานะออกจากการทำงานของคำสั่งสุดท้าย แต่ยังสามารถตั้งค่าสถานะการส่งคืนได้อย่างชัดเจนด้วยreturnbuiltin และเราเห็นความแตกต่างบางอย่างที่นี่:

  • bashและmksh(ตั้งแต่ R41 การถดถอย ^ Wchange แนะนำโดยเจตนา ) จะตัดทอนหมายเลข (บวกหรือลบ) เป็น 8 บิต ดังนั้นสำหรับตัวอย่างเช่นreturn 1234จะตั้ง$?ไป210, return -- -1จะตั้ง$?255
  • zshและpdksh(และอนุพันธ์อื่นที่ไม่ใช่mksh) อนุญาตเลขจำนวนเต็มฐานสิบแบบ 32 บิต (-2 31ถึง 2 31 -1) (และตัดจำนวนเป็น32 บิต)
  • ashและyashอนุญาตให้จำนวนเต็มบวกใด ๆ จาก 0 ถึง 2 31 -1 และส่งกลับข้อผิดพลาดสำหรับตัวเลขใด ๆ จากนั้น
  • ksh93สำหรับreturn 0การreturn 320ตั้งค่า$?ตามที่เป็น แต่สำหรับสิ่งอื่นให้ตัดเหลือ 8 บิต ระวังดังที่ได้กล่าวไปแล้วว่าการส่งคืนตัวเลขระหว่าง 256 ถึง 320 อาจทำให้เกิดkshการฆ่าตัวตายเมื่อออกจาก
  • rcและesอนุญาตให้ส่งคืนรายการอะไรก็ได้

นอกจากนี้โปรดทราบว่าบางเชลล์ใช้ค่าพิเศษของ$?/ $statusเพื่อรายงานเงื่อนไขข้อผิดพลาดบางอย่างที่ไม่ใช่สถานะการออกของกระบวนการเช่น127หรือ126สำหรับคำสั่งไม่พบหรือไม่สามารถเรียกใช้งานได้ (หรือข้อผิดพลาดทางไวยากรณ์ในไฟล์ที่มา) ...


1
an exit code to their parentto get the *status* of their childและ คุณได้เพิ่มการเน้นที่ "สถานะ" คือexit codeและ*status*เดียวกันได้หรือไม่ กรณีใช่สิ่งที่มาของการมีสองชื่อคืออะไร? กรณีไม่เหมือนกันคุณสามารถให้คำจำกัดความ / การอ้างอิงสถานะได้หรือไม่?
n611x007

2
มี 3 ตัวเลขอยู่ที่นี่ รหัสทางออก : exit()หมายเลขที่ผ่านมา ออกจากสถานะ : หมายเลขที่ได้จากการwaitpid()ซึ่งรวมถึงรหัสทางออกหมายเลขสัญญาณและว่ามีแกนทิ้ง และจำนวนที่เชลล์บางตัวมีให้ในหนึ่งในตัวแปรพิเศษของพวกเขา ( $?, $status) นั่นคือการแปลงสถานะการออกในลักษณะที่มีรหัสการออกในกรณีที่มีการเลิกจ้างตามปกติ แต่ยังมีข้อมูลสัญญาณถ้า กระบวนการนี้ถูกฆ่า (โดยทั่วไปเรียกว่าสถานะการออก ) นั่นคือทั้งหมดที่อธิบายไว้ในคำตอบของฉัน
Stéphane Chazelas

1
ฉันเห็นขอบคุณ! ฉันขอขอบคุณที่ทราบอย่างชัดเจนถึงความแตกต่างที่นี่ นิพจน์เหล่านี้เกี่ยวกับทางออกถูกใช้แทนกันได้ในบางสถานที่ที่มีค่า ตัวแปรของเชลล์มีชื่อ (ทั่วไป) หรือไม่? ดังนั้นฉันขอแนะนำให้ทำการล้างอย่างชัดเจนก่อนที่จะลงรายละเอียดเกี่ยวกับเปลือกหอย ฉันขอแนะนำให้แทรกคำอธิบาย (จากความคิดเห็นของคุณ) หลังจากวรรคแรกหรือย่อหน้าที่สองของคุณ
n611x007

1
คุณสามารถชี้ไปที่เครื่องหมายคำพูด POSIX ที่บอกว่าเกี่ยวกับ 7 บิตแรกเป็นสัญญาณได้หรือไม่ ทั้งหมดที่ฉันสามารถหาได้คือ> 128ส่วนหนึ่ง: "สถานะการออกของคำสั่งที่ยกเลิกเพราะได้รับสัญญาณจะถูกรายงานมากกว่า 128" pubs.opengroup.org/onlinepubs/9699919799/utilities/…
Ciro Santilli 事件新疆中心中心法轮功六四事件

1
@cuonglm ฉันไม่คิดว่าจะให้บริการแบบสาธารณะที่ใดก็ได้ผ่าน HTTP คุณยังสามารถรับได้จาก gmane ผ่าน NNTP ค้นหา id ของข้อความefe764d811849b34eef24bfb14106f61@austingroupbugs.net(จาก 2015-05-06) หรือXref: news.gmane.org gmane.comp.standards.posix.austin.general:10726
Stéphane Chazelas

23

เมื่อกระบวนการจบการทำงานจะส่งคืนค่าจำนวนเต็มไปยังระบบปฏิบัติการ สำหรับตัวแปร Unix ส่วนใหญ่ค่านี้จะได้รับ modulo 256: ทุกอย่าง แต่บิตลำดับต่ำจะถูกละเว้น สถานะของกระบวนการลูกจะถูกส่งกลับไปยังผู้ปกครองผ่านจำนวนเต็ม 16 บิตซึ่ง

  • บิต 0–6 (บิตต่ำลำดับ 7) คือหมายเลขสัญญาณที่ใช้เพื่อฆ่ากระบวนการหรือ 0 ถ้ากระบวนการออกตามปกติ
  • บิตที่ 7 ถูกตั้งค่าถ้ากระบวนการถูกฆ่าโดยสัญญาณและแกนทิ้ง
  • บิต 8-15 เป็นรหัสออกของกระบวนการหากกระบวนการออกตามปกติหรือ 0 ถ้ากระบวนการถูกฆ่าโดยสัญญาณ

สถานะถูกส่งคืนโดยการwaitเรียกของระบบหรือหนึ่งในพี่น้อง POSIX ไม่ได้ระบุการเข้ารหัสที่แน่นอนของสถานะทางออกและหมายเลขสัญญาณ มันให้เท่านั้น

  • วิธีที่จะบอกว่าสถานะการออกสอดคล้องกับสัญญาณหรือการออกปกติ
  • วิธีเข้าถึงรหัสออกหากกระบวนการออกจากปกติ
  • วิธีเข้าถึงหมายเลขสัญญาณหากกระบวนการถูกฆ่าโดยสัญญาณ

พูดอย่างเคร่งครัดไม่มีทางออกรหัสเมื่อกระบวนการที่ถูกฆ่าตายโดยสัญญาณ: สิ่งที่มีแทนคือทางออกสถานะ

ในเชลล์สคริปต์ที่ออกจากสถานะของคำสั่ง$?จะมีการรายงานผ่านทางตัวแปรพิเศษ ตัวแปรนี้เข้ารหัสสถานะการออกในลักษณะที่ไม่ชัดเจน:

  • หากกระบวนการออกได้ตามปกติแล้ว$?คือสถานะทางออกของมัน
  • หากกระบวนการนั้นถูกฆ่าโดยสัญญาณก็$?คือ 128 บวกกับจำนวนสัญญาณในระบบส่วนใหญ่ POSIX เฉพาะเอกสารที่$?มากกว่า 128 ในกรณีนี้ ksh93 เพิ่ม 256 แทน 128 ฉันไม่เคยเห็นตัวแปร unix ที่ทำสิ่งอื่นนอกจากเพิ่มค่าคงที่ไปยังหมายเลขสัญญาณ

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

SIGINT เป็นสัญญาณที่ 2 สำหรับตัวแปรยูนิกซ์ส่วนใหญ่ดังนั้นจึง$?เป็น 128 + 2 = 130 สำหรับกระบวนการที่ SIGINT ถูกฆ่า คุณจะเห็น 129 สำหรับ SIGHUP, 137 สำหรับ SIGKILL ฯลฯ


พูดมากขึ้นและมากขึ้นถึงจุดกว่าของฉันแม้ว่ามันจะบอกว่าในสาระสำคัญสิ่งเดียวกัน คุณอาจต้องการที่จะชี้แจงว่า$?เป็นเปลือกหอยเหมือนบอร์นเท่านั้น ดูเพิ่มเติมyashสำหรับพฤติกรรมที่แตกต่าง (แต่ยังคง POSIX) นอกจากนี้ตาม POSIX + XSI (Unix) a kill -2 "$pid"จะส่ง SIGINT ไปยังกระบวนการ แต่หมายเลขสัญญาณจริงอาจไม่เป็น 2 ดังนั้น $? จะไม่จำเป็นต้องเป็น 128 + 2 (หรือ 256 + 2 หรือ 384 + 2) แต่kill -l "$?"จะกลับมาINTซึ่งเป็นสาเหตุที่ฉันจะแนะนำให้พกพาไม่ให้อ้างอิงหมายเลขตัวเอง
Stéphane Chazelas

8

ขึ้นอยู่กับเปลือกของคุณ จากbash(1)หน้าคนส่วนSHELL GRAMMARส่วนย่อยคำสั่งง่าย ๆ :

ค่าตอบแทนของคำสั่งง่ายๆคือ [ ... ] 128+ nถ้าคำสั่งจะถูกยกเลิกโดยสัญญาณn

เนื่องจากSIGINTในระบบของคุณคือหมายเลขสัญญาณ 2 ค่าส่งคืนคือ 130 เมื่อรันภายใต้ Bash


1
คุณค้นพบสิ่งนี้ในโลกได้อย่างไรหรือแม้กระทั่งรู้ว่าจะมองที่ไหน ฉันคำนับต่ออัจฉริยะของคุณ
Cory Klein

1
@CoryKlein: ประสบการณ์ส่วนใหญ่ โอ้และคุณอาจต้องการsignal(7)หน้าคนด้วย
Ignacio Vazquez-Abrams

สิ่งที่เย็น; คุณรู้หรือไม่ว่าฉันมีไฟล์ใน C พร้อมค่าคงที่เหล่านั้นโดยบังเอิญ +1
Rui F Ribeiro

@CoryKlein ทำไมคุณไม่เลือกนี่เป็นคำตอบที่ถูกต้อง
Rui F Ribeiro

3

ดูเหมือนจะเป็นสถานที่ที่เหมาะสมที่จะพูดถึงว่า SVr4 เปิดตัว Waitid () ในปี 1989 แต่ดูเหมือนว่าจะไม่มีโปรแกรมสำคัญที่จะใช้งาน waitid () อนุญาตให้เรียกข้อมูล 32 บิตเต็มจากรหัส exit ()

ประมาณ 2 เดือนที่ผ่านมาฉันเขียนส่วนรอ / งานควบคุมของ Bourne Shell อีกครั้งเพื่อใช้ waitid () แทนที่จะเป็น waitpid () สิ่งนี้ทำเพื่อลบข้อ จำกัด ที่ปิดบังรหัสการออกด้วย 0xFF

อินเทอร์เฟซ waitid () นั้นสะอาดกว่าเดิมมากที่การใช้งาน wait () ก่อนหน้านี้ยกเว้นการเรียก cwait () จาก UNOS จาก 1980

คุณอาจสนใจอ่าน man page ที่:

http://schillix.sourceforge.net/man/man1/bosh.1.html

และตรวจสอบส่วน "การทดแทนพารามิเตอร์" ที่กำลังดูอยู่ในหน้า 8

มีการแนะนำตัวแปรใหม่. sh. * สำหรับอินเทอร์เฟซ waitid () อินเทอร์เฟซนี้ไม่มีความหมายที่คลุมเครืออีกต่อไปสำหรับตัวเลขที่ทราบราคา $ แล้ว? และทำให้การเชื่อมต่อง่ายขึ้นมาก

โปรดทราบว่าคุณต้องมี Waitid ที่เข้ากันได้กับ POSIX () เพื่อให้สามารถใช้คุณสมบัตินี้ดังนั้น Mac OS X และ Linux ในปัจจุบันไม่ได้เสนอสิ่งนี้ แต่การรอ Waitid () จะถูกจำลองในการเรียก waitpid () ดังนั้น แพลตฟอร์มที่ไม่ใช่ POSIX คุณจะยังคงได้รับเพียง 8 บิตจากรหัสออก

กล่าวโดยย่อ: .sh.status เป็นรหัสออกตัวเลข,. sh.code เป็นเหตุผลในการออกตัวเลข

เพื่อความสะดวกในการพกพาที่ดีขึ้นมี: .sh.codename สำหรับรุ่นข้อความของเหตุผลการออกเช่น "DUMPED" และ. sh.termsig ชื่อ singal สำหรับสัญญาณที่ยุติกระบวนการ

เพื่อการใช้งานที่ดีขึ้นมีค่า. sh.codename ที่ไม่เกี่ยวข้องกับค่าสองค่า: "NOEXEC" และ "NOTFOUND" ที่ใช้เมื่อโปรแกรมไม่สามารถเปิดใช้งานได้เลย

FreeBSD แก้ไขข้อผิดพลาดของ kerlnel waitid () ภายใน 20 ชั่วโมงหลังจากรายงานของฉัน Linux ยังไม่ได้เริ่มด้วยการแก้ไข ฉันหวังว่า 26 ปีหลังจากแนะนำคุณสมบัตินี้ที่อยู่ใน POSIX ตอนนี้ระบบปฏิบัติการทั้งหมดจะสนับสนุนในไม่ช้า


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