อะไรคือความแตกต่างระหว่าง "source x", " x” และ“ ./x” ใน Bash?


11

ฉันมีแหล่งทุบตีหนึ่งแหล่งrun.shดังนี้

#!/bin/bash
if [ $# -ne 1 ]; then
    exit
fi
...

เมื่อฉันรันมันสองวิธีมีพฤติกรรมที่แตกต่างกัน วิธีแรกคือ

source run.sh

มันจะปิดสถานีหลังจากดำเนินการ วิธีที่สองคือ

./run.sh

การดำเนินการนี้จะทำให้สคริปต์ทำงานให้เสร็จ ฉันกำลังถามว่ามีคำสั่งให้ออกจากสคริปต์ทุบตีสำหรับทั้งสองsource run.shและ./run.shการดำเนินการ ฉันได้ลองแล้วreturnเช่นกันซึ่งใช้งานไม่ได้กับ./run.shการทำงาน

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

คำตอบ:


16

ก่อนที่จะตอบฉันคิดว่าต้องการคำอธิบายบางอย่าง ลองวิเคราะห์สามบรรทัดต่อไปนี้:

source run.sh
. run.sh
./run.sh

สองบรรทัดแรกเหมือนกันว่า: ในความเป็นจริงนามแฝงสำหรับ. sourceสิ่งที่เรียกsourceใช้งานเชลล์สคริปต์ในบริบทปัจจุบันดังนั้นการเรียกไปยังexitจะออกจากเชลล์

บรรทัดที่สาม (ซึ่งเป็นสิ่งที่ทำให้คุณสับสน) ไม่มีอะไรเกี่ยวข้องกับบรรทัดอื่น ./run.shเป็นเพียงเส้นทางและเป็นเช่นเดียวกับ (ตัวอย่าง) หรือ/home/user/run.sh /usr/bin/somethingโปรดจำไว้เสมอว่าคำสั่งในเชลล์นั้นคั่นด้วยช่องว่าง ดังนั้นในกรณีนี้คำสั่งไม่ได้.แต่เป็น./run.sh: ซึ่งหมายความว่า sub-shell จะถูกดำเนินการและexitจะมีผลกับ sub-shell


5

สามวิธี:

คุณสามารถใส่สคริปต์ในฟังก์ชันและใช้การส่งคืนเท่านั้น

#!/usr/bin/env bash
main() {
    ...
    return 1
    ...
}
main "$@"

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

if [[ $- = *i* ]]; then
    return 1
else
    exit 1
fi

คุณสามารถลองกลับมาและถ้ามันล้มเหลวออก

return 1 2>/dev/null || exit 1

คำใบ้ใด ๆ เกี่ยวกับคาถาเวทมนต์ใช้$- = *i* งานอย่างไร?
deadbeef404

@ deadbeef404 พารามิเตอร์พิเศษ-เก็บค่าสถานะตัวเลือกที่ใช้งานอยู่ในปัจจุบัน การทดสอบจะตรวจสอบว่า-iมีการใช้งานสถานะหรือไม่ ดูgnu.org/software/bash/manual/html_node/Special-Parameters.html
geirha

1

คิดว่าคำสั่ง 'แหล่งที่มา' ในคำสั่ง 'รวม' ใช้เนื้อหาของการโต้แย้งและเรียกใช้ราวกับว่ามันถูกเรียกใช้โดยตรง ในกรณีนี้คำสั่งของคุณคือ 'แหล่งที่มา' พร้อมด้วยอาร์กิวเมนต์ 'run.sh' และ run.sh จะถูกดำเนินการเหมือนกับคุณพิมพ์เนื้อหาของ run.sh ลงในบรรทัดคำสั่งของคุณ

เมื่อคุณเรียกใช้ './run.sh', './run.sh' เป็นคำสั่งของคุณและไม่มีข้อโต้แย้งใด ๆ เนื่องจากไฟล์นี้เป็นข้อความธรรมดาและไม่ใช่ไบนารีเชลล์ของคุณจึงมองหาล่ามที่ shebang ('#!' ในบรรทัดแรก) และค้นหา '/ bin / bash' ดังนั้นเชลล์ของคุณจะเริ่มต้นอินสแตนซ์ใหม่ของ bash และเนื้อหาของ run.sh จะถูกเรียกใช้ภายในอินสแตนซ์ใหม่นี้

ในอินสแตนซ์แรกเมื่อ bash มาถึงคำสั่ง 'exit' มันจะถูกดำเนินการเหมือนกับคุณพิมพ์ลงในบรรทัดคำสั่ง ในอินสแตนซ์ที่สองจะถูกดำเนินการในกระบวนการทุบตีเปลือกของคุณเริ่มต้นดังนั้นเฉพาะอินสแตนซ์ของการทุบตีนี้ได้รับคำสั่ง 'exit'

เมื่อคุณพิมพ์บรรทัดลงในทุบตีสิ่งใดก่อนที่ช่องว่างแรกจะถือว่าเป็นคำสั่งและสิ่งที่ตามมาจะถือว่าเป็นข้อโต้แย้ง คำสั่ง '.' เป็นนามแฝงของ 'แหล่งที่มา' เมื่อคุณเรียกใช้ ' run.sh 'the'. ' เป็นคำสั่งที่เป็นของตัวเองเนื่องจากแยกออกจากอาร์กิวเมนต์ของช่องว่าง เมื่อคุณเรียกใช้ './run.sh' คำสั่งของคุณคือ './run.sh' และ '.' เป็นส่วนหนึ่งของเส้นทางสัมพัทธ์ที่จะ run.sh ด้วย ' แสดงโฟลเดอร์ปัจจุบันของคุณ


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