คำสั่ง Unix ที่ส่งคืนรหัสส่งคืนทันทีหรือไม่


28

มีคำสั่ง Unix มาตรฐานที่ทำสิ่งที่คล้ายกับตัวอย่างของฉันด้านล่าง

$ <cmd here> 56
$ echo Return code was $?
Return code was 56
$

<cmd here>ควรเป็นสิ่งที่สามารถ fork-execed และปล่อยให้ 56 เป็นรหัสทางออกเมื่อกระบวนการออก exitและreturnเปลือก builtins ไม่เหมาะสมสำหรับสิ่งที่ฉันกำลังมองหาเพราะพวกเขามีผลต่อการกล่าวอ้างเปลือกตัวเองด้วยการออกออกมาจากมัน <some cmd>ควรเป็นสิ่งที่ฉันสามารถดำเนินการในบริบทที่ไม่ใช่เปลือก - เช่นเรียกจากสคริปต์ Python subprocessด้วย

เช่น/usr/bin/falseออกจากทันทีด้วยรหัสส่งคืน 1 แต่ฉันต้องการควบคุมรหัสที่ส่งคืนนั้นอย่างแน่นอน ฉันสามารถบรรลุผลลัพธ์เดียวกันโดยเขียนสคริปต์ตัวคลุมของฉันเอง

$ cat my-wrapper-script.sh # i.e., <some cmd> = ./my-wrapper-script.sh
#!/usr/bin/bash
exit $1
$ ./my-wrapper-script.sh 56
$ echo $?
56

แต่ฉันหวังว่าจะมีคำสั่ง Unix มาตรฐานที่สามารถทำสิ่งนี้ให้ฉันได้


10
exitเป็นคนเดียวที่ฉันคิดได้ แต่มันมีแนวโน้มที่จะจบเชลล์ของคุณ bash -c 'exit 56'หรือbash -c "exit $1"อาจทำงานให้คุณ
ทิมเคนเนดี้

12
แล้วไง(exit 56)ล่ะ
cuonglm

6
ดูเหมือนว่าXYProblem จริงๆ : เป้าหมายสูงสุดของเรื่องนี้คืออะไร? ทำไมคุณต้องมีคำสั่งที่ส่งกลับเป็นรหัสทางออกหมายเลขที่คุณให้?
Olivier Dulac

1
คุณมีtrueและfalseบิวด์อินถ้าคุณต้องการส่งคืน 0 หรือ 1
Gardenhead

1
ที่เกี่ยวข้อง: โปรแกรมที่เล็กที่สุด (ไม่ใช่พกพา) เพื่อส่งคืนค่าคงที่เวลาคอมไพล์: muppetlabs.com/~breadbox/software/tiny/teensy.html
Florian Castellane

คำตอบ:


39
  1. returnฟังก์ชั่นพื้นฐานจะทำงานและหลีกเลี่ยงการจำเป็นที่จะต้องเปิดและปิดเปลือกอื่น (ตามทิมเคนเนดี้คิดเห็น 's ):

    freturn() { return "$1" ; } 
    freturn 56 ; echo $?

    เอาท์พุท:

    56
  2. ใช้exitใน subshell:

    (exit 56)

    ด้วยกระสุนอื่นksh93ที่หมายถึงการฟอร์กกระบวนการพิเศษดังนั้นจึงมีประสิทธิภาพน้อยกว่าข้างต้น

  3. bash/ zsh/ ksh93หลอกลวงเท่านั้น:

    . <( echo return 56 )

    (ซึ่งหมายถึงกระบวนการพิเศษ (และ IPC ด้วยไพพ์))

  4. zshฟังก์ชั่นแลมบ์ดา:

    (){return 56}

ความคิดที่ดี น่าเสียดายที่คำถามดั้งเดิมของฉันยังไม่ชัดเจนพอ - ต้อง "เปิดและปิดเปลือกอื่น" เกือบจะเป็นข้อกำหนดของสิ่งที่ฉันต้องการจะทำ ฉันแก้ไขคำถามของฉันเพื่อขอสิ่งนั่น<some cmd>คือสิ่งที่สามารถทำได้ ()
Chris

2
@Chris: สำหรับคำสั่ง shell คุณสามารถทำให้มัน execve () สามารถแปลงเป็น/bin/sh -c ...originalcommand...
psmears

3
ฉันผิดหวังเล็กน้อยที่ = 56 ไม่ทำงาน
โจชัว

@ โจชัว: บางทีมันอาจจะ? แต่แล้วความรู้สึกนี้ก็ประสบความสำเร็จและคุณมีเงิน $? ตั้งค่าเป็น 0 ... ;)
Olivier Dulac

@OlivierDulac: มันไม่ได้ มันคายข้อผิดพลาดในการแยก
Joshua

17

ไม่มีคำสั่ง UNIX มาตรฐานสำหรับการคืนค่าเฉพาะ ลิขสิทธิ์ GNU หลัก Utilies ให้trueและfalseเพียง

อย่างไรก็ตามคุณสามารถใช้สิ่งนี้ด้วยตนเองได้อย่างง่ายดายretดังนี้

#include <stdlib.h>
int main(int argc, char *argv[]) {
  return argc > 1 ? atoi(argv[1]) : 0;
}

รวบรวม:

cc ret.c -o ret

และเรียกใช้:

./ret 56 ; echo $?

พิมพ์:

56

หากคุณต้องการให้สิ่งนี้ทำงานได้ทุกที่ (ที่ bash พร้อมใช้งานคือ) โดยไม่ต้องติดตั้งเครื่องมือพิเศษใด ๆ คุณอาจต้องใช้คำสั่งต่อไปนี้ตามที่ @TimKennedy แนะนำในความคิดเห็น:

bash -c 'exit 56'

โปรดทราบว่าช่วงที่ถูกต้องของค่าตอบแทนรวม 0..255


1
trueและfalseอยู่ใน Unix (และ POSIX) ด้วยเช่นกันไม่เพียง แต่ใน GNU
Stéphane Chazelas

@ StéphaneChazelasขอบคุณที่ชี้ให้เห็น เมื่อ OP กล่าวถึงทุบตีฉันคิดว่า GNU - แม้ว่าคำถามจะระบุว่า 'Unix'
tmh

14

หากคุณต้องการสถานะออกจะถูกตั้งค่าโดยคำสั่งดำเนินการ ไม่มีคำสั่งเฉพาะสำหรับ1นั้น แต่คุณสามารถใช้ล่ามของภาษาใด ๆ ที่มีความสามารถในการออกด้วยสถานะออกโดยพลการ shเป็นสิ่งที่ชัดเจนที่สุด:

sh -c 'exit 56'

ด้วยshการนำไปใช้งานส่วนใหญ่นั้น จำกัด ไว้ที่รหัสทางออก 0 ถึง 255 ( shจะยอมรับค่าที่มากขึ้น แต่อาจตัดทอนหรือทำให้สัญญาณถูกส่งไปยังกระบวนการที่ดำเนินการshเช่นเดียวกับ ksh93 สำหรับรหัส 257 ถึง 320)

โค้ดทางออกสามารถเป็นค่าจำนวนเต็มใด ๆ ( int) ได้ แต่โปรดทราบว่าคุณต้องดึงข้อมูลกลับมาด้วยwaitid()อินเทอร์เฟซดังนั้นค่าจะไม่ถูกตัดทอนเป็น 8 บิต (บน Linux แต่ก็ยังถูกตัดทอนด้วยwaitid()) ดังนั้นทำไมจึงเป็นเรื่องยาก (และไม่ใช่ความคิดที่ดี) ในการใช้รหัสออกที่ด้านบน 255 (ใช้ 0-123 สำหรับการทำงานปกติ)

อีกวิธีหนึ่งคือ:

awk 'BEGIN{exit 56}'
perl -e 'exit 56'
python -c 'exit(56)'
expect -c 'exit 56'

(สิ่งที่ไม่ตัดทอนรหัสออกเป็น 8 บิต)

ด้วย NetBSD findคุณสามารถ:

find / -exit 56

1exitคือคำสั่งมาตรฐานในการทำเช่นนั้น แต่การเป็นเชลล์บิวด์อินพิเศษไม่มีข้อกำหนดว่าจะต้องมีคำสั่งตามชื่อในระบบไฟล์เช่นสำหรับบิวด์อินปกติและระบบส่วนใหญ่จะไม่รวมหนึ่ง


3
/* Public domain, http://creativecommons.org/publicdomain/zero/1.0/ */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc,char **argv) {
    if(!strcasecmp(argv[0],"true")) return 0;
    else if (!strcasecmp(argv[0],"false")) return 1;
    else if(argc<2) {fputs("One argument required\n",stderr);return 1;}
    else if(!strcasecmp(argv[argc-1],"true")) return 0;
    else if(!strcasecmp(argv[argc-1],"false")) return 1;
    else return atoi(argv[argc-1]);
}

บันทึกในไฟล์ชื่อreturncode.cและgcc -o returncode returncode.c


ในบันทึกกึ่งที่เกี่ยวข้อง: 1) การใช้ใบอนุญาต CC0 โดยไม่ต้องตั้งชื่อตัวเองว่าเป็นผู้รับรองอาจไม่ใช่ความคิดที่ดีและคุณควรทำเช่นนี้ 2) โปรแกรมเล็ก ๆ นี้มีความสำคัญต่อลิขสิทธิ์ของคุณมากเกินไป อาจรวมถึงการออกใบอนุญาต
Rhymoid

2
(1) ผมไม่เข้าใจว่าทำไมคุณกำลังใช้argv[argc-1]แทนและทำไมคุณไม่ได้บ่นถ้าargv[1] argc>2(2) ฉันจะมีความโน้มเอียงที่จะทำargv[1]การทดสอบก่อนที่จะargv[0]ทดสอบให้ผู้ใช้สามารถพูดtrue 56หรือแทนfalse 56 returncode 56คุณไม่ได้ให้ข้อความหากargv[0]เป็นคำและargc>0- ที่อาจทำให้เกิดความสับสน (3) ฉันหมกมุ่นอยู่กับความง่ายดายในการใช้ดังนั้นฉันต้องการใช้แทนstrcasecmp strcmp(4) ฉันมักจะตรวจสอบพารามิเตอร์และไม่ใช้ค่าส่งคืนatoiโดยไม่ตรวจสอบ สำหรับโปรแกรม 2 like แบบนี้ฉันคิดว่ามันไม่สำคัญ
G-Man กล่าวว่า 'Reinstate Monica'

@ G-Man ทั้งtrueมิได้falseกระบวนการโต้แย้งใด ๆ ในระบบ Linux
ThePiercingPrince

ตกลงถูกต้องพวกเขาไม่ประมวลผลอาร์กิวเมนต์ใด ๆ รวมถึงargv[0]; โปรแกรม/bin/trueและ/bin/falseไฟล์ปฏิบัติการที่แตกต่างกันโดยมีรหัสการออกฮาร์ดโค้ด คุณเขียนโปรแกรมที่สามารถติดตั้งได้ทั้ง ( trueและfalseเชื่อมโยง) ซึ่งฉลาด แต่คำถามจะถามวิธีรับสถานะการออกที่ผู้ใช้ระบุ โปรแกรมของคุณตอบคำถามนั้น แต่ถ้าติดตั้งภายใต้ชื่อไฟล์อื่น ตราบใดที่คุณกำลังดูargvอยู่ฉันเชื่อว่าการทำตามที่ฉันแนะนำจะรักษาระดับความฉลาดโดยหลีกเลี่ยงความต้องการลิงก์ที่สาม
G-Man กล่าวว่า 'Reinstate Monica'

0

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

username@host$ $(exit 42)
username@host$ echo $?
42

ฉันทดสอบสิ่งนี้กับ Cygwin Bash ในตอนนี้และมันใช้ได้กับฉัน

แก้ไข: ขออภัยฉันพลาดส่วนหนึ่งของการเรียกใช้มันนอกบริบทเชลล์ ในกรณีเช่นนี้จะไม่ช่วยถ้าไม่มีการห่อไว้ใน.shสคริปต์และเรียกใช้งานจากสภาพแวดล้อมของคุณ


4
$(exit 42)พยายามเรียกใช้งานเอาต์พุตexit 42เป็นคำสั่งแบบง่าย ๆ ซึ่งไม่ค่อยมีเหตุผล (มันจะไม่ทำงานด้วยyash) (exit 42)(ยังทำงานexitใน subshell แต่ปล่อยเอาท์พุทของมันคนเดียว) จะทำให้รู้สึกมากขึ้นและจะพกพาได้มากขึ้น (แม้จะ csh หรือเชลล์บอร์น)
Stéphane Chazelas
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.