ความแตกต่างระหว่าง Return และ Exit ในฟังก์ชั่น Bash


429

อะไรคือความแตกต่างระหว่างคำสั่งreturnและexitคำสั่งในฟังก์ชั่น Bash ที่เกี่ยวกับรหัสทางออก?


55
Protip: พิมพ์help <command>เชลล์ของคุณเพื่อรับข้อมูลว่าเชลล์บิวด์อินจะทำอะไร ในกรณีของคุณhelp returnและhelp exit
SiegeX

คำตอบ:


318

จากman bashบนreturn [n];

ทำให้ฟังก์ชั่นหยุดการทำงานและคืนค่าที่ระบุโดย n ไปยังผู้เรียก หากไม่ได้ระบุไว้ n สถานะการส่งคืนจะเป็นของคำสั่งสุดท้ายที่ดำเนินการในเนื้อความของฟังก์ชัน

... เมื่อexit [n]:

ทำให้เชลล์ออกโดยมีสถานะเป็น n หากไม่ได้ระบุไว้สถานะการออกจะเป็นของคำสั่งสุดท้ายที่ดำเนินการ กับดักบน EXIT ถูกดำเนินการก่อนที่เชลล์จะหยุดทำงาน

แก้ไข:

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

แก้ไข 2:

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

ทุกคำสั่งดำเนินการในเปลือกผลิตท้องถิ่น "รหัสทางออก": มันกำหนด$?ตัวแปรรหัสที่สามารถนำมาใช้กับif, &&และผู้ประกอบการอื่น ๆ ที่จะตามเงื่อนไขรันคำสั่งอื่น ๆ

รหัสทางออกเหล่านี้ (และค่าของ$?ตัวแปร) จะถูกรีเซ็ตโดยการดำเนินการคำสั่งแต่ละครั้ง

อนึ่งรหัสทางออกของคำสั่งสุดท้ายที่เรียกใช้โดยสคริปต์จะใช้เป็นรหัสออกจากสคริปต์เองตามที่เห็นโดยกระบวนการเรียก

ในที่สุดฟังก์ชั่นเมื่อเรียกใช้ทำหน้าที่เป็นคำสั่งเชลล์ที่เกี่ยวกับรหัสออก รหัสทางออกของฟังก์ชั่น ( ภายในฟังก์ชั่น) returnจะถูกตั้งค่าโดยใช้ ดังนั้นเมื่อในการทำงานreturn 0ของฟังก์ชั่นการดำเนินการฟังก์ชั่นสิ้นสุดลงให้รหัสออกจาก 0


10
ไม่แน่นอน มันจะส่งคืนค่าจากเชลล์ปัจจุบันเสมอ ไม่สำคัญว่าคุณจะอยู่ในฟังก์ชั่นหรือไม่
Diego Sevilla

10
ความคิดเห็นเกี่ยวกับการแก้ไขของคุณ: ผมอาจจะทำให้เกิดความสับสนและค่าที่ส่งคืนรหัสออก แต่func(){ return 50; };func;echo $?เสียงสะท้อน 50. ดังนั้น$?ตัวแปรเปลือกดูเหมือนจะไม่ถูก จำกัด exitให้
lecodesportif

8
" $?ขยายเป็นสถานะออกของไปป์ไลน์เบื้องหน้าที่เรียกใช้งานล่าสุด" ทางออกนั้นอาจมาจากเชลล์ในรูปแบบของการเรียกไปที่exit(หรือกดปุ่มสิ้นสุดสคริปต์) หรือในรูปแบบของการเรียกไปยังreturnภายในฟังก์ชัน
SiegeX

11
@lecodesportif: $? กระบวนการ / สคริปต์ปัจจุบันถูก จำกัดexitหรือผลลัพธ์ของคำสั่งสุดท้ายที่ดำเนินการโดยสคริปต์นี้ ดังนั้นหากบรรทัดสคริปต์สุดท้ายของคุณคือการเรียกใช้ฟังก์ชันนั้นและฟังก์ชันนั้นจะคืนค่า 50 ใช่$?คุณจะสร้างกระบวนการที่เรียกว่าคุณคือ 50 อย่างไรก็ตามนั่นไม่ได้เกี่ยวข้องกับสิ่งreturnนั้นเพราะนี่คือ จำกัด ให้สคริปต์ปัจจุบัน มันจะถูกส่งกลับเฉพาะเมื่อการเรียกใช้ฟังก์ชันนี้เป็นประโยคสุดท้ายของสคริปต์ exitอย่างไรก็ตามให้สคริปต์ดำเนินการให้เสร็จสิ้นและส่งคืนค่านั้นตาม$? กระบวนการเรียกใช้
Diego Sevilla

11
-1 สำหรับการทำให้สับสนกับบรรทัด " returnไม่มีอะไรเกี่ยวข้องกับรหัสทางออก" การทดลองบอกฉันว่าไม่มีความแตกต่างการทำงานระหว่างโค้ดส่งคืนของฟังก์ชันและโค้ดออกของสคริปต์
Jack

296

returnจะทำให้ฟังก์ชันปัจจุบันออกนอกขอบเขตในขณะที่exitจะทำให้สคริปต์สิ้นสุด ณ จุดที่เรียกใช้ นี่คือตัวอย่างโปรแกรมที่จะช่วยอธิบายสิ่งนี้:

#!/bin/bash

retfunc()
{
    echo "this is retfunc()"
    return 1
}

exitfunc()
{
    echo "this is exitfunc()"
    exit 1
}

retfunc
echo "We are still here"
exitfunc
echo "We will never see this"

เอาท์พุต

$ ./test.sh
this is retfunc()
We are still here
this is exitfunc()

17
ตัวอย่างที่ดี นอกจากนี้คุณยังสามารถแสดงค่าออกจาก 1 $?ใน
Diego Sevilla

48
โปรดทราบว่าฟังก์ชั่นนี้จะไม่พิมพ์ "เรายังอยู่ที่นี่" หากคุณเพิ่ม "set -e" ก่อนการเรียกไปที่ "retfunc"
ไมเคิล

4
อย่างไรก็ตามecho fnord | while read x; do exitfunc; done; echo "still here"จะพิมพ์ "ยังอยู่ที่นี่" ดูเหมือนว่ามีการออกเฉพาะwhileเชลล์ย่อยในสถานการณ์นี้
tripleee

วิธีแก้ปัญหาโดยประมาณคือdone || exit $?แต่นั้นน่าเกลียดและไม่เทียบเท่ากันอย่างแม่นยำ
tripleee

2
+1 มันอาจมีประโยชน์ในการเพิ่ม: `` ` returnจะทำให้ฟังก์ชั่นปัจจุบันหรือสคริปต์ที่มาจากขอบเขต '' '
Isaac

56

ฉันไม่คิดว่าใครจะตอบคำถามได้อย่างสมบูรณ์เพราะพวกเขาไม่ได้อธิบายวิธีการใช้งานของทั้งสอง ตกลงฉันคิดว่าเรารู้ว่าการออกจากการฆ่าสคริปต์ซึ่งจะถูกเรียกและคุณสามารถกำหนดสถานะให้กับมันเช่นออกหรือออก 0 หรือออก 7 และอื่น ๆ สามารถใช้เพื่อกำหนดวิธีที่สคริปต์ถูกบังคับให้หยุดถ้าเรียกโดยสคริปต์อื่นเป็นต้นพอออก

return เมื่อเรียกว่าจะส่งคืนค่าที่ระบุเพื่อระบุพฤติกรรมของฟังก์ชั่นมักจะเป็น 1 หรือ 0 ตัวอย่างเช่น:

    #!/bin/bash
    isdirectory() {
      if [ -d "$1" ]
      then
        return 0
      else
        return 1
      fi
    echo "you will not see anything after the return like this text"
    }

ตรวจสอบเช่นนี้:

    if isdirectory $1; then echo "is directory"; else echo "not a directory"; fi

หรือเช่นนี้

    isdirectory || echo "not a directory"

ในตัวอย่างนี้การทดสอบสามารถใช้เพื่อระบุว่าพบไดเรกทอรี โปรดสังเกตว่าสิ่งใดหลังจากการส่งคืนจะไม่ถูกดำเนินการในฟังก์ชัน 0 เป็นจริง แต่เท็จเป็น 1 ในเชลล์ซึ่งแตกต่างจากโปรแกรมอื่น ๆ

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับฟังก์ชั่น: http://www.linuxjournal.com/content/return-values-bash-functions

หมายเหตุ: ฟังก์ชั่น isdirectory มีวัตถุประสงค์เพื่อการเรียนการสอนเท่านั้น นี่ไม่ควรเป็นวิธีที่คุณทำเช่นนั้นในสคริปต์จริง


3
หรือเพียงแค่ใช้test -d $1เพื่อให้ได้ผลลัพธ์เดียวกัน if <check> return else returnไม่เคยทำ <check>เพียงอย่างเดียวจะทำสิ่งเดียวกันในทุกภาษาที่ฉันรู้
erikbwork

4
เพื่อให้ชัดเจนยิ่งขึ้นเกี่ยวกับสิ่งที่ erik พูด: isdirectory() { [ -d "$1" ]; }จะทำงานอย่างแม่นยำเหมือนกับที่คุณมีที่นี่: ค่าส่งคืนเริ่มต้นของฟังก์ชั่นเชลล์ไม่ว่าจะถึงจุดสิ้นสุดของรหัสหรือโดยreturnไม่มีข้อโต้แย้งเป็นของ คำสั่งล่าสุด
ชาร์ลส์ดัฟฟี่

11
นักวิจารณ์คนอื่นที่นี่กำลังวิจารณ์ลักษณะของตัวอย่างของ Mike Q เมื่อเขาพูดถึงพฤติกรรมของreturnข้อความ มันเป็นความจริงที่ตัวอย่างของเขาเรียบง่ายและไม่ควรใช้ในการผลิต แต่มันง่ายดังนั้นมันจึงทำงานของเขาได้ดี ไม่มีอะไรผิดปกติกับมัน
Mike S

ขอบคุณ Mike S ใช่ฉันยอมรับว่าตัวอย่างที่ง่ายที่สุดอธิบายถึงทางออกกลับมาได้ดีที่สุด ความคิดเห็นอื่น ๆ อย่างแน่นอนที่ถูกต้องและควรได้รับการพิจารณามากขึ้น coders ทุบตีขั้นสูง ;-)
ไมค์ Q

1
บางคนอาจบอกว่ามันไม่เกี่ยวข้องกับคำถามแต่เกี่ยวข้องกับและตอบปัญหาที่ฉันมีซึ่งทำให้ฉันพบคำถามนี้ :-)
Jesse Steele

33

โปรดจำไว้ว่าฟังก์ชั่นนั้นอยู่ภายในสคริปต์และโดยปกติจะส่งคืนจากสิ่งที่ถูกเรียกโดยใช้คำสั่ง return การเรียกสคริปต์ภายนอกเป็นอีกเรื่องหนึ่งโดยสิ้นเชิงและสคริปต์มักจะยุติด้วยข้อความสั่ง exit

ความแตกต่าง "ระหว่างคำสั่ง return และ exit ในฟังก์ชั่น BASH ที่เกี่ยวกับรหัสทางออก" นั้นน้อยมาก ทั้งคืนสถานะไม่ใช่ค่าต่อ se สถานะศูนย์หมายถึงความสำเร็จในขณะที่สถานะอื่น ๆ (1 ถึง 255) หมายถึงความล้มเหลว คำสั่ง return จะกลับไปที่สคริปต์จากที่ซึ่งถูกเรียกในขณะที่คำสั่ง exit จะจบสคริปต์ทั้งหมดจากที่ใดก็ตามที่พบ

return 0  # returns to where the function was called.  $? contains 0 (success).

return 1  # returns to where the function was called.  $? contains 1 (failure).

exit 0  # exits the script completely.  $? contains 0 (success).

exit 1  # exits the script completely.  $? contains 1 (failure).

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

โปรดจำไว้ว่าการกลับมาและออกให้กลับรหัสสถานะที่ 0-255 $?ในใช้ได้ คุณไม่สามารถสิ่งอื่นใดลงในรหัสสถานะ (เช่นส่งคืน "cat"); มันจะไม่ทำงาน แต่สคริปต์สามารถส่งกลับสาเหตุต่าง ๆ 255 สาเหตุที่ทำให้เกิดความล้มเหลวโดยใช้รหัสสถานะ

คุณสามารถตั้งค่าตัวแปรที่มีอยู่ในสคริปต์การโทรหรือผลลัพธ์เสียงสะท้อนในฟังก์ชั่นและใช้การทดแทนคำสั่งในสคริปต์การโทร; แต่วัตถุประสงค์ของการส่งคืนและออกคือการส่งรหัสสถานะไม่ใช่ค่าหรือผลลัพธ์การคำนวณอย่างที่ใคร ๆ คาดหวังในภาษาการเขียนโปรแกรมเช่น C


25

บางครั้งคุณเรียกใช้สคริปต์ที่ใช้หรือ.source

. a.sh

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

หากคุณรวม a returnไว้ในตัวa.shมันจะหยุดการประมวลผลสคริปต์


1
แต่เมื่อฉันเรียกใช้ a.sh ฉันได้รับข้อผิดพลาดreturn: can only 'return' from a function or sourced scriptซึ่งทำให้สคริปต์ทั่วไปไม่เหมาะสม
ปีเตอร์ - Reinstate Monica

ในระดับสูงสุดของสคริปต์ไม่เหมาะกับallสถานการณ์ การใช้.หรือsourceเรียกใช้สคริปต์ในเชลล์ปัจจุบันแทนที่จะวางไข่เชลล์ย่อย สคริปต์ต้องรู้ว่าจะใช้อย่างไร ความฉิบหายให้กับผู้ใช้ที่ทำตรงข้าม ส่วนตัวผมขอแนะนำให้อ่านสคริปต์ก่อนที่จะเรียกใช้ในครั้งแรก
Jesse Chisholm

3
เคล็ดลับน่ากลัวฉันมาข้ามคือการใช้trapฟังก์ชั่นสำหรับการERR EXITแล้วครั้งแรกที่บันทึกรหัสทางออกของคำสั่งที่ล้มเหลวerrCode=$?แล้วออกจากสคริปต์ (ที่มาหรือไม่) มีreturn $errCode || exit $errCodeที่||หมายถึง "ถ้าผมไม่สามารถกลับเพราะผมก็ไม่ได้มา เพียงออกจากแทน "
dragon788

6

ในคำง่าย ๆ (ส่วนใหญ่สำหรับมือใหม่ในการเขียนโปรแกรม) เราสามารถพูดได้ว่า

`return` : exits the function,
`exit()` : exits the program(called as process while running)

นอกจากนี้หากคุณสังเกตว่านี่เป็นพื้นฐานมาก แต่ ...

`return` : is the keyword
`exit()` : is the function

1
ในสคริปต์ทุบตีexitจะมีฟังก์ชั่นไม่returnมากไปกว่านั้น พวกเขาเป็นคำสั่งในตัว พวกเขาไม่ได้จองคำ
ปีเตอร์ - Reinstate Monica

6
  • exitยุติกระบวนการปัจจุบัน ; มีหรือไม่มีรหัสทางออกพิจารณาระบบนี้มากกว่าฟังก์ชั่นโปรแกรม โปรดทราบว่าเมื่อการจัดหาexitจะสิ้นสุดเชลล์อย่างไรก็ตามเมื่อทำงานจะเป็นเพียงexitสคริปต์

  • return จากฟังก์ชั่นกลับไปที่คำแนะนำหลังจากการโทรโดยมีหรือไม่มีรหัสส่งคืน returnเป็นทางเลือกและเป็นนัยในตอนท้ายของฟังก์ชัน returnสามารถใช้ได้ภายในฟังก์ชั่นเท่านั้น

ฉันต้องการที่จะเพิ่มในขณะที่มีที่มามันไม่ใช่เรื่องง่าย exitที่สคริปต์จากภายในฟังก์ชั่นโดยไม่ต้องฆ่าเชลล์ ฉันคิดว่าตัวอย่างจะดีกว่าในสคริปต์ 'ทดสอบ'

#!/bin/bash
function die(){
   echo ${1:=Something terrible wrong happen}
   #... clean your trash
   exit 1
}

[ -f /whatever/ ] || die "whatever is not available"
# now we can proceed
echo "continue"

ทำดังต่อไปนี้:

user$ ./test
Whatever is not available
user$

test - และ - เชลล์จะปิด

user$ . ./test
Whatever is not available

เท่านั้นtestจะเสร็จสิ้นและจะแจ้งให้

วิธีแก้ไขคือปิดโพรซีเดอร์ใน(และ)

#!/bin/bash
function die(){
   echo $(1:=Something terrible wrong happen)
   #... clean your trash
   exit 1
}

( # added        
    [ -f /whatever/ ] || die "whatever is not available"
    # now we can proceed
    echo "continue"
) # added

ตอนนี้ทั้งสองกรณีเท่านั้นที่testจะออก


การเพิ่ม(และ)วางบล็อกนั้นใน sub-shell โดยไม่ต้องทำ.คำสั่ง (ซอร์ส) อย่างมีประสิทธิภาพเหมือนกับว่าคุณได้รันสคริปต์ทดสอบตามปกติซึ่งอยู่ใน sub-shell ถ้าสคริปต์ไม่ทำงาน.หรือsourceคุณมี 2 sub-shells อย่างมีประสิทธิภาพ
Jesse Chisholm

3

คำถามของ OP: อะไรคือความแตกต่างระหว่างคำสั่ง return และ exit ในฟังก์ชั่น BASH ที่เกี่ยวกับรหัสทางออก?

ต้องมีการชี้แจงบางอย่าง:

  • คำสั่ง (return | exit) ไม่จำเป็นสำหรับการยุติการดำเนินการของ (function | shell) A (ฟังก์ชั่น | เชลล์) จะยุติลงเมื่อถึงจุดสิ้นสุดของรายการโค้ดแม้ว่าจะไม่มีคำสั่ง (return | exit)
  • คำสั่ง (return | exit) ไม่จำเป็นต้องส่งค่ากลับจากการยกเลิก (function | shell) ทุกกระบวนการมีตัวแปร $ ในตัวหรือไม่ ซึ่งมักจะมีค่าตัวเลข มันเป็นตัวแปรพิเศษที่ไม่สามารถตั้งค่าเป็น "? = 1" แต่ถูกตั้งค่าในรูปแบบพิเศษเท่านั้น (ดูด้านล่าง *) ค่าของ $? หลังจากคำสั่งสุดท้ายที่จะดำเนินการใน (เรียกว่า function | sub shell) คือค่าที่ถูกส่งกลับไปที่ (function caller | parent shell) นั่นเป็นความจริงไม่ว่าคำสั่งสุดท้ายที่ดำเนินการคือ ("return [n]" | "exit [n]") หรือล้วน ("return" หรืออย่างอื่นที่เกิดขึ้นเป็นคำสั่งสุดท้ายในรหัสฟังก์ชั่นที่เรียกว่า

ในรายการหัวข้อย่อยด้านบนเลือกจาก "(x | y)" ไม่ว่าจะเป็นรายการแรกหรือรายการที่สองเสมอเพื่อรับข้อความเกี่ยวกับฟังก์ชั่น & return หรือ shells & exit ตามลำดับ

สิ่งที่ชัดเจนคือพวกเขาทั้งสองแบ่งปันการใช้งานร่วมกันของตัวแปรพิเศษ $? เพื่อส่งผ่านค่าขึ้นไปหลังจากที่ยุติ

* สำหรับวิธีพิเศษที่ $? สามารถตั้งค่า:

  • เมื่อฟังก์ชั่นที่เรียกว่ายุติและกลับไปที่มันเป็นผู้โทรแล้ว $? ในผู้โทรจะเท่ากับมูลค่าสุดท้ายของ $? ในฟังก์ชั่นสิ้นสุด
  • เมื่อพาเรนต์เชลล์โดยปริยายหรือรออย่างชัดเจนบนเชลล์ย่อยเดียวและปล่อยโดยการยกเลิกเชลล์ย่อยนั้นแล้ว $? ใน parent parent จะเท่ากับมูลค่าสุดท้ายของ $? ในเชลล์ย่อยที่ถูกยกเลิก
  • บางฟังก์ชั่นในตัวสามารถปรับเปลี่ยน $ ได้ ขึ้นอยู่กับผลลัพธ์ของพวกเขา แต่บางคนทำไม่ได้
  • ฟังก์ชั่นในตัว "return" และ "exit" เมื่อตามด้วยอาร์กิวเมนต์ตัวเลขทั้ง $? ด้วยอาร์กิวเมนต์และยุติการดำเนินการ

มันเป็นที่น่าสังเกตว่า $? สามารถกำหนดค่าโดยการเรียก exit ใน sub shell เช่นนี้

# (exit 259)
# echo $?
3  

4
ในกรณีที่บางคนพลาดมันexit 259echos 3เพราะค่าทางออกสุดท้ายคือไบต์เดียว 259 % 256 = 3
Jesse Chisholm

0

ประการแรกreturnคือคำหลักและexitเพื่อนของฉันคือฟังก์ชั่น

ที่กล่าวว่านี่เป็นคำอธิบายที่ง่ายที่สุด

return มันคืนค่าจากฟังก์ชั่น

exit ออกจากหรือละทิ้งเชลล์ปัจจุบัน


ไม่ได้จริงๆ! คุณผิดทางตรรกะ ออกเป็นฟังก์ชั่นในขณะที่returnเป็นคำหลัก ผลตอบแทนนั้นเป็นมากกว่าแค่รหัสทางออกซึ่งเป็นเหตุผลที่การเปรียบเทียบไม่ยุติธรรม
Ahmad Awais

ฉันเขียนมันเพื่อทำให้จุดที่ชัดเจนยิ่งขึ้นซึ่งฉันพยายามทำ ขอบคุณที่ช่วยฉันทำอย่างนั้น
Ahmad Awais

4
ทั้งexitมิได้returnเป็น "คำหลัก" หรือเป็นคู่มือโทรทุบตีพวกเขา "คำสงวน" ไม่มีใครเป็น "ฟังก์ชั่น" อย่างใดอย่างหนึ่งในความหมายของฟังก์ชั่นทุบตี ทั้งคู่เป็นคำสั่งในตัวในภาษา bash lingo (มีเป็นฟังก์ชัน C ห้องสมุดมาตรฐานที่เรียกว่าexit()และการเขียนโปรแกรมภาษา C มีคำสงวนreturnแต่ผู้ที่ไม่ควรจะสับสนกับคำสั่งทุบตีแม้ว่าความหมายของพวกเขามีความคล้ายคลึงซอกแซก.)
ปีเตอร์ - คืนสิทธิ์ให้กับโมนิกา
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.