วิธีใดก็ตามที่จะออกจากสคริปต์ทุบตี แต่ไม่ออกจากสถานี


183

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

สคริปต์ของฉันrun.shคาดว่าจะดำเนินการโดยการจัดหาโดยตรงหรือมาจากสคริปต์อื่น

แก้ไข: เพื่อให้เฉพาะเจาะจงมากขึ้นมีสองสคริปต์run2.shเป็น

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

และrun.shเป็น

...
exit
...

เมื่อฉันเรียกใช้โดย. run2.shและถ้ามันชนexitcodeline ในrun.shฉันต้องการให้หยุดที่สถานีและอยู่ที่นั่น แต่การใช้exitเทอร์มินัลทั้งหมดจะถูกปิด

PS: ฉันพยายามใช้returnแล้ว แต่echocodeline จะยังคงได้รับการดำเนินการ ....


5
ฉันจริง ๆ ต้องถามจริงๆ: ทำไมคุณถึงออกจากในสคริปต์ที่มา?
Ignacio Vazquez-Abrams

3
คำสั่ง exit ไม่ควรยุติเซสชัน / ล็อกอินเทอร์มินัลของคุณ หากคุณใช้exit 0เพื่อยุติสคริปต์หลังจากประสบความสำเร็จเมื่อคุณเรียกใช้สคริปต์ของคุณเช่น./test.shคุณควรเห็นผลลัพธ์ แต่คอนโซลของคุณจะยังคงเปิดอยู่
Ben Ashton

คุณสามารถใช้shellคำสั่งที่เปิดในความเป็นจริง terminal terminal ประสบการณ์ของตัวเอง exitแต่เป็นว่านี้ไม่ได้เกิดขึ้นกับ โดยปกติแล้ว Exit จะให้การควบคุมกลับไปยังสคริปต์หลัก
Willem Van Onsem

คำตอบ:


258

ปัญหา "" จริง ๆ แล้วคือคุณกำลัง sourcing และไม่ดำเนินการสคริปต์ เมื่อคุณแหล่งที่มาของไฟล์เนื้อหาของมันจะถูกดำเนินการในเปลือกปัจจุบันแทนการวางไข่ subshell ดังนั้นทุกอย่างรวมถึงทางออกจะส่งผลต่อเชลล์ปัจจุบัน

แทนการใช้คุณจะต้องการใช้exitreturn


2
นี่คือคำอธิบายอื่นที่ฉันพบว่ามีประโยชน์: askubuntu.com/a/53179/148337
3cheesewheel

แม้ว่าจะถูกต้อง แต่นี่ไม่ใช่คำตอบที่ดี มันไม่สนใจว่าสคริปต์การโทรอาจประกาศตัวแปรหรือฟังก์ชั่นที่เรียกว่าสคริปต์ต้องการการเข้าถึง ดีกว่าที่จะอธิบายวิธีการตั้งรหัสส่งคืนแล้วดำเนินการในruns.sh@ruakh มีคำตอบที่ดีกว่าสำหรับคำถามนี้
MikeSchinkel

5
เกิดอะไรขึ้นถ้าฟังก์ชั่นการโทรซ้อนกัน? เช่นสาย b, b สาย c, c ต้องการออกจาก a และ b ทันที
Michael

แหล่งที่มาเกือบจะเหมือนกับการคัดลอกวาง มันเป็นเรื่องดีที่จะใช้sh <script>หรือbash <script>ถ้าใครต้องการที่จะเรียกใช้สคริปต์และยุติในบางจุด
peterchaula

42

ใช่; คุณสามารถใช้แทนreturn exitจุดประสงค์หลักของมันคือการส่งคืนจากฟังก์ชันเชลล์ แต่ถ้าคุณใช้ภายในsource-d script มันจะส่งคืนจากสคริปต์นั้น

ในฐานะ§4.1 "Bourne Shell Builtins" ของคู่มืออ้างอิง Bashทำให้:

     return [n]

ทำให้เกิดฟังก์ชั่นเพื่อออกจากเปลือกที่มีค่าตอบแทนn หากไม่ได้ระบุnค่าส่งคืนคือสถานะออกของคำสั่งสุดท้ายที่ดำเนินการในฟังก์ชัน สิ่งนี้อาจถูกใช้เพื่อยุติการทำงานของสคริปต์ที่ถูกเรียกใช้งานด้วย.(หรือsource) builtin โดยส่งคืนnหรือสถานะการออกของคำสั่งสุดท้ายที่ดำเนินการภายในสคริปต์เป็นสถานะการออกของสคริปต์ คำสั่งใด ๆ ที่เกี่ยวข้องกับกับRETURNดักจะถูกดำเนินการก่อนที่จะดำเนินการต่อหลังจากฟังก์ชั่นหรือสคริปต์ สถานะกลับไม่เป็นศูนย์ถ้าreturnจะใช้ฟังก์ชั่นด้านนอกและไม่ได้ในระหว่างการดำเนินการของสคริปต์โดยหรือ.source


3
returnสามารถใช้ได้จากฟังก์ชั่นเท่านั้น หากคุณใช้returnและดำเนินการเป็นเชลล์สคริปต์ (เช่นsh run.sh) ทุบตีจะรายงานข้อผิดพลาด - return: can only ส่งคืน 'จากฟังก์ชันหรือสคริปต์ที่มา'
Tzunghsing David Wong

@TzungsingDavidWong: คุณรู้หรือไม่ว่าคำตอบนี้เป็นคำพูดจากคู่มืออ้างอิงอย่างเป็นทางการ และข้อความแสดงข้อผิดพลาดที่คุณอ้างถึงเห็นด้วยกับคำตอบนี้แทนที่จะอ้างสิทธิ์ของคุณ?
ruakh

ฉันไม่เห็นด้วยกับคุณ ฉันเพียงต้องการชี้ให้เห็นว่าreturnจะไม่ทำงานหากสคริปต์ทำงานเป็นเชลล์สคริปต์และไม่ได้ดำเนินการโดย (หรือsource) BTW ฉันจะหาเอกสารเกี่ยวกับได้source -dที่ไหน
Tzunghsing David Wong

9

แทนที่จะเรียกใช้สคริปต์โดยใช้. run2.shคุณสามารถเรียกใช้โดยใช้sh run2.shหรือbash run2.sh

เชลล์ย่อยใหม่จะเริ่มขึ้นเพื่อเรียกใช้สคริปต์จากนั้นจะปิดเมื่อสิ้นสุดสคริปต์โดยเปิดเชลล์อื่นไว้


ถ้าเป็นเช่นนั้นทำไมพารามิเตอร์ที่สองsh "." run2.sh?
CHAN

@ H0WARD คุณถูกต้องฉันลืมลบจุด ฉันได้แก้ไขคำตอบแล้ว
Viorel Mirea

1
OP ระบุแหล่งที่มาอย่างชัดเจนว่าเป็นข้อกำหนด
Jonathan Neufeld

4

คุณสามารถเพิ่มคำสั่งออกพิเศษหลังจากคำสั่งส่งคืน / คำสั่งเพื่อให้ทั้งสองดำเนินการสคริปต์จากบรรทัดคำสั่งและการจัดหาจากสถานี

ตัวอย่างรหัสออกในสคริปต์:

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

บรรทัดที่มีexitคำสั่งจะไม่ถูกเรียกเมื่อคุณส่งสคริปต์หลังreturnคำสั่ง

เมื่อคุณรันสคริปต์returnคำสั่งจะให้ข้อผิดพลาด /dev/nullดังนั้นเราปราบปรามข้อความข้อผิดพลาดโดยการส่งต่อไปยัง


3

ที่จริงฉันคิดว่าคุณอาจสับสนกับวิธีที่คุณส่งเสียง run a scriptshoult

หากคุณใช้shเพื่อเรียกใช้สคริปต์ให้พูดsh ./run2.shแม้ว่าสคริปต์ฝังตัวลงท้ายด้วยexitหน้าต่างเทอร์มินัลของคุณจะยังคงอยู่

อย่างไรก็ตามถ้าคุณใช้.หรือsourceหน้าต่างเทอร์มินัลของคุณจะออก / ปิดเช่นกันเมื่อสิ้นสุดการห้อย

สำหรับรายละเอียดเพิ่มเติมโปรดอ้างอิงถึงความแตกต่างระหว่างการใช้งานshกับsourceอะไร?


2

นี่เหมือนกับที่คุณใส่ฟังก์ชั่น run ไว้ใน script run2.sh คุณใช้รหัสออกภายในการทำงานในขณะที่แหล่งไฟล์ run2.sh ของคุณใน bash tty หากการให้ฟังก์ชัน run นั้นมีพลังในการออกจากสคริปต์ของคุณและให้ run2.sh ที่จะออกจาก terminator จากนั้น cuz ฟังก์ชั่น run จะมีอำนาจออกจาก teminator ของคุณ

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

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

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

อย่างไรก็ตามฉันอนุมัติกับ Kaz ว่าเป็นปัญหาการออกแบบ


ไม่ชัดเจนจากข้อความสิ่งที่คำตอบนี้พยายามทำ แต่แน่นอนไม่สามารถแก้คำถามได้
Luís de Sousa

2

ฉันมีปัญหาเดียวกันและจากคำตอบข้างต้นและจากสิ่งที่ฉันเข้าใจสิ่งที่ทำงานให้ฉันในที่สุดคือ:

  1. มีบรรทัด shebang ที่เรียกใช้สคริปต์ที่ต้องการตัวอย่างเช่น

    #!/bin/bashใช้bashในการรันสคริปต์

ฉันมีสคริปต์กับ shebang ทั้งสองประเภท ด้วยเหตุนี้การใช้shหรือ.ไม่น่าเชื่อถือเนื่องจากนำไปสู่การปฏิบัติที่ไม่ถูกต้อง (เช่นเมื่อสคริปต์หยุดทำงานไม่สมบูรณ์)

คำตอบคือ

    • ตรวจสอบให้แน่ใจว่าสคริปต์มี shebang ดังนั้นจึงไม่มีข้อสงสัยเกี่ยวกับตัวจัดการที่ต้องการ
    • chmod ไฟล์. sh เพื่อให้สามารถดำเนินการได้ (chmod +x file.sh)
    • เรียกใช้โดยตรงโดยไม่มีshหรือ.

      (./myscript.sh)

หวังว่านี่จะช่วยคนที่มีคำถามหรือปัญหาที่คล้ายกัน


1

ฉันคิดว่าสิ่งนี้เกิดขึ้นเพราะคุณกำลังเรียกใช้บนโหมดต้นทางด้วยจุด

. myscript.sh

คุณควรจะเรียกใช้ใน subshell:

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

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


คุณไม่ต้องการพา ธ เต็มไปยังสคริปต์หากใช้. myscript.shงานได้ ./myscript.shที่ส่วนใหญ่คุณอาจต้อง
ÁlvaroGonzález

1

มันถูกต้องที่สคริปต์ที่มากับสคริปต์ที่เรียกใช้นั้นreturnเทียบกับexitเพื่อเปิดเซสชันเดียวกัน

นี่คือเคล็ดลับที่เกี่ยวข้องหากคุณต้องการสคริปต์ที่ควรเปิดเซสชันไว้ไม่ว่าจะมีแหล่งที่มาหรือไม่

ตัวอย่างต่อไปนี้สามารถเรียกใช้โดยตรงเช่นfoo.shหรือมาเหมือน/. foo.sh source foo.shไม่ว่าจะเปิดเซสชันใดก็ตามหลังจาก "ออก" $@สตริงจะถูกส่งเพื่อให้ฟังก์ชั่นที่มีการเข้าถึงการขัดแย้งสคริปต์ด้านนอกของ

#!/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 "$@";

ผลลัพธ์เทอร์มินัล:

$ foo.sh
$ คุณต้องการ XYZ หรือไม่ (Y / N): n
$ foo.sh
$ คุณต้องการ XYZ หรือไม่ (Y / N): n
$ |
(หน้าต่างเทอร์มินัลยังคงเปิดอยู่และยอมรับอินพุตเพิ่มเติม)

สิ่งนี้มีประโยชน์สำหรับการทดสอบการเปลี่ยนแปลงสคริปต์ในเทอร์มินัลเดียวอย่างรวดเร็วในขณะที่เก็บรหัสเศษไว้ใต้เมนexit/ returnในขณะที่คุณทำงาน นอกจากนี้ยังอาจทำให้โค้ดพกพามากขึ้นในแง่หนึ่ง (ถ้าคุณมีสคริปต์มากมายที่อาจหรืออาจไม่ได้รับการเรียกในรูปแบบที่แตกต่างกัน) แม้ว่าจะเป็น clunky น้อยกว่าที่จะใช้returnและexitเหมาะสม


0

หากเทอร์มินัลอีมูเลเตอร์ของคุณไม่มีให้-holdคุณสามารถฆ่าเชื้อสคริปต์ที่มาและทำให้เทอร์มินัลค้างไว้ด้วย:

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

มิฉะนั้นคุณสามารถใช้ $TERM -hold -e script


0

ตรวจสอบให้แน่ใจว่าได้ส่งคืนพร้อมค่าส่งคืนที่คาดไว้ ถ้าคุณใช้ออกเมื่อคุณจะพบทางออกมันจะออกจากเปลือกฐานของคุณเนื่องจากแหล่งที่มาไม่ได้สร้างกระบวนการอื่น (เช่น)


0

การเขียนสคริปต์ที่มีความปลอดภัยที่จะทำงานเป็นทั้งสคริปต์เปลือกหรือมาเป็นแฟ้ม rc เป็นสคริปต์ที่สามารถตรวจสอบและเปรียบเทียบ$0และ$BASH_SOURCEและตรวจสอบว่าexitสามารถใช้ได้อย่างปลอดภัย

นี่คือข้อมูลโค้ดสั้น ๆ สำหรับสิ่งนั้น

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

-1

1) การออก 0 จะออกมาจากสคริปต์หากประสบความสำเร็จ

2) ทางออก 1 จะออกมาจากสคริปต์หากเกิดข้อผิดพลาด

คุณสามารถลองสองสิ่งข้างต้นได้ตามคำขอของคุณ

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