อะไรคือความแตกต่างระหว่างการเรียกใช้งานสคริปต์ Bash เทียบกับการจัดหามัน


คำตอบ:


344

คำตอบสั้น ๆ

การจัดหาสคริปต์จะเรียกใช้คำสั่งในกระบวนการเชลล์ปัจจุบัน

การเรียกใช้สคริปต์จะเรียกใช้คำสั่งในกระบวนการเชลล์ใหม่

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

หากคุณยังสับสนอยู่โปรดอ่านต่อ

คำศัพท์

ในการชี้แจงความสับสนทั่วไปเกี่ยวกับไวยากรณ์ที่จะดำเนินการและไวยากรณ์ของแหล่งที่มา:

./myscript

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

myscript

ซึ่งจะดำเนินการ ถ้าไฟล์เป็นปฏิบัติการและอยู่ในไดเรกทอรีในบางmyscript$PATH

source myscript

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

. myscript

นี้จะยังแหล่งที่มา myscriptนี้ "สะกด" อย่างเป็นทางการอย่างใดอย่างหนึ่งตามที่กำหนดโดยPOSIX ทุบตีกำหนดsourceเป็นนามแฝงของจุด

สาธิต

พิจารณาmyscript.shเนื้อหาต่อไปนี้:

#!/bin/sh
# demonstrate setting a variable
echo "foo: "$(env | grep FOO)
export FOO=foo
echo "foo: "$(env | grep FOO)
# demonstrate changing of working directory
echo "PWD: "$PWD
cd somedir
echo "PWD: "$PWD

ก่อนที่เราจะรันสคริปต์ก่อนอื่นเราจะตรวจสอบสภาพแวดล้อมปัจจุบัน:

$ env | grep FOO
$ echo $PWD
/home/lesmana

FOOไม่ได้กำหนดตัวแปรและเราอยู่ในโฮมไดเรกทอรี

ตอนนี้เรารันไฟล์:

$ ./myscript.sh
foo:
foo: FOO=foo
PWD: /home/lesmana
PWD: /home/lesmana/somedir

ตรวจสอบสภาพแวดล้อมอีกครั้ง:

$ env | grep FOO
$ echo $PWD
/home/lesmana

FOOไม่ได้ตั้งค่าตัวแปรและไดเรกทอรีการทำงานไม่เปลี่ยนแปลง

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

ตอนนี้เรามาไฟล์:

$ source myscript.sh
foo:
foo: FOO=foo
PWD: /home/lesmana
PWD: /home/lesmana/somedir

ตรวจสอบสภาพแวดล้อมอีกครั้ง:

$ env | grep FOO
FOO=foo
$ echo $PWD
/home/lesmana/somedir

ตัวแปร FOO ถูกตั้งค่าและไดเรกทอรีการทำงานมีการเปลี่ยนแปลง

การจัดหาสคริปต์ไม่ได้สร้างเชลล์ใหม่ คำสั่งทั้งหมดจะทำงานในเชลล์ปัจจุบันและการเปลี่ยนแปลงสภาพแวดล้อมจะมีผลในเชลล์ปัจจุบัน

โปรดทราบว่าในตัวอย่างง่ายๆนี้ผลลัพธ์ของการดำเนินการจะเหมือนกับการจัดหาสคริปต์ กรณีนี้ไม่จำเป็นเสมอไป

การสาธิตอื่น

พิจารณาสคริปต์ต่อไปนี้pid.sh:

#!/bin/sh
echo $$

(ตัวแปรพิเศษ$$ขยายเป็น PID ของกระบวนการเชลล์ปัจจุบัน)

พิมพ์ PID ของเชลล์ปัจจุบันก่อน:

$ echo $$
25009

ส่งสคริปต์:

$ source pid.sh
25009

ดำเนินการสคริปต์บันทึก PID:

$ ./pid.sh
25011

แหล่งที่มาอีกครั้ง:

$ source pid.sh
25009

ดำเนินการอีกครั้ง:

$ ./pid.sh
25013

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

สรุป

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

ความแตกต่างคือ:

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

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


ดูสิ่งนี้ด้วย:


2
การใช้แหล่งข้อมูลหนึ่งครั้งคือการสร้างรูปแบบพื้นฐานของไฟล์กำหนดค่าสำหรับสคริปต์ของคุณ คุณเริ่มต้นด้วยการตั้งค่าตัวแปรต่าง ๆ ให้เป็นค่าเริ่มต้นจากนั้นแหล่งที่มาในรูปแบบเช่น myscript.conf - และสคริปต์ที่มานั้นสามารถมีคำสั่งการมอบหมายที่แทนที่ค่าใด ๆ ที่คุณต้องการ เนื่องจากสคริปต์ที่มาไม่ได้ขึ้นต้นด้วย # / bin / bash จึงไม่สนับสนุนให้ดำเนินการโดยตรง
LawrenceC

ดังนั้นแหล่งที่มานั้นเหมือนกับการเรียกใช้ในขอบเขตส่วนกลางและการดำเนินการสร้างขอบเขตท้องถิ่นใหม่ สิ่งนี้สามารถขยายไปยังฟังก์ชั่นในสคริปต์หรือไม่? เพื่อรันฟังก์ชั่น (ปกติ) หรือเพื่อ "แหล่ง" มันได้หรือไม่
aliteralmind

2
มีความแตกต่างระหว่างการใช้งานsource myscript.shและ. myscript.sh?
Holloway

2
จริงไม่แตกต่างกันถ้าใช้ทุบตี แหล่งที่มาเป็นนามแฝงที่จะจุดในทุบตี
lesmana

1
ฉันรักมันเมื่อมีคนให้ตัวอย่างที่ซับซ้อนเช่นนั้นแม้กระทั่งมือใหม่ Linux เช่นตัวฉันเองก็สามารถเข้าใจได้ ขอบคุณ!
Julius

21

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

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

หากคุณมีข้อโต้แย้งตำแหน่งในเปลือกปัจจุบันพวกเขาจะไม่เปลี่ยนแปลง

ดังนั้นถ้าฉันมีไฟล์a.shที่มี:

echo a $*

และฉันทำ:

$ set `date`
$ source ./a.sh

ฉันชอบ:

a Fri Dec 11 07:34:17 PST 2009

โดย:

$ set `date`
$ ./a.sh

ให้ฉัน:

a

หวังว่าจะช่วย


5
แม้ว่าคำตอบนี้ถูกต้องในทุกวิถีทางฉันพบว่ามันยากที่จะเข้าใจเพราะมันแสดงให้เห็นโดยใช้แนวคิดอื่น (การตั้งค่าพารามิเตอร์ตำแหน่ง) ซึ่งในความคิดของฉันยิ่งทำให้สับสนมากกว่าความแตกต่างของการจัดหาและดำเนินการเอง
เลสมานา

9

การจัดหาเป็นหลักเหมือนกับการพิมพ์แต่ละบรรทัดของสคริปต์ในที่พร้อมรับคำสั่งทีละครั้ง ...

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


6

นอกเหนือจากข้างต้นการเรียกใช้สคริปต์ตามที่./myscriptกำหนดให้ต้องมีการอนุญาตให้ใช้งานสำหรับไฟล์ myscript ในขณะที่การจัดหาไม่จำเป็นต้องมีการอนุญาตให้เรียกใช้งาน นั่นคือเหตุผลที่chmod +x myscriptไม่จำเป็นก่อนsource myscript


2
จริง bash myscriptแต่ถ้าเป็นปัญหาที่คุณสามารถเรียกใช้
Daniel Beck

5

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


3

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


2

sourceคำสั่งรันสคริปต์ที่จัดเตรียมไว้(สิทธิ์ในการเรียกใช้งานนั้นไม่บังคับ )ในสภาพแวดล้อมเชลล์ปัจจุบันในขณะที่./เรียกใช้งานสคริปต์ปฏิบัติการที่จัดเตรียมไว้ให้ในเชลล์ใหม่

ตรวจสอบคำตอบนี้เช่น: https://superuser.com/a/894748/432100

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