อะไรคือความแตกต่างระหว่างการจัดหา ('.' หรือ 'แหล่งที่มา') และการเรียกใช้ไฟล์ใน bash?


76

ความแตกต่างระหว่างการเรียกใช้งานสคริปต์เช่นนี้:

./test.sh

และดำเนินการสคริปต์เช่นนี้:

. test.sh?

ฉันลองสคริปต์สองบรรทัดแบบง่าย ๆ เพื่อดูว่าฉันสามารถค้นหาได้หรือไม่ว่ามีความแตกต่าง:

#!/bin/bash
ls

แต่ทั้งสอง. test.shและ./test.shส่งคืนข้อมูลเดียวกัน


ขออภัยหากนี่เป็นข้อมูลซ้ำซ้อน - เมื่อทำการตรวจสอบเพิ่มเติมฉันพบบางหน้าเว็บที่มีข้อมูลที่เกี่ยวข้องโดยค้นหา 'bash dot' แทน 'bash'
Natan

3
เช่นเดียวกับที่test.shไม่ได้เป็นเช่นเดียวกับ./test.sh(คนแรกที่จะเรียกPATHการค้นหา) เพื่อให้มี. test.shและ. ./test.shที่แตกต่างกันในทางเดียวกัน (อดีตจะเรียกPATHการค้นหา) กระสุนจำนวนมากดูเหมือนจะรวม.อยู่ในตอนท้ายPATHเมื่อทำการ.ค้นหาเส้นทาง แต่พฤติกรรมนี้ไม่ได้มาตรฐาน ดังนั้นจึงเป็นที่ถูกต้องมากขึ้นเพื่อเปรียบเทียบtest.shเทียบ. test.shและเทียบ./test.sh . ./test.sh
jw013

คำตอบ:


83

./test.shทำงานtest.shเป็นโปรแกรมแยกต่างหาก มันอาจจะเกิดขึ้นจะเป็นสคริปต์ทุบตีถ้าไฟล์เริ่มต้นด้วยtest.sh #!/bin/bashแต่มันอาจเป็นอย่างอื่นโดยสิ้นเชิง

. ./test.shรันรหัสของไฟล์test.shภายในอินสแตนซ์ที่กำลังทำงานของ bash มันทำงานราวกับว่าไฟล์เนื้อหาtest.shได้รับการรวมเป็นข้อความแทนที่จะเป็น. ./test.shบรรทัด (เกือบ: มีรายละเอียดเล็กน้อยที่แตกต่างกันเช่นมูลค่าของ$BASH_LINENOและพฤติกรรมของreturnbuiltin)

source ./test.shเหมือนกับ. ./test.shในทุบตี (ในเปลือกหอยอื่นsourceอาจแตกต่างกันเล็กน้อยหรือไม่มีอยู่ทั้งหมด.สำหรับการรวมอยู่ในมาตรฐาน POSIX)

ความแตกต่างที่เห็นได้บ่อยที่สุดระหว่างการเรียกใช้สคริปต์แยกด้วย./test.shและรวมถึงสคริปต์ที่มีใน.ตัวคือถ้าtest.shสคริปต์ตั้งค่าตัวแปรสภาพแวดล้อมบางอย่างด้วยกระบวนการแยกต่างหากจะมีการตั้งค่าสภาพแวดล้อมของกระบวนการลูกเท่านั้นในขณะที่มีการรวมสคริปต์ ของกระบวนการเปลือก แต่เพียงผู้เดียวถูกตั้งค่า หากคุณเพิ่มบรรทัดfoo=barในtest.shและecho $fooท้ายสคริปต์โทรคุณจะเห็นความแตกต่าง:

$ cat test.sh
#!/bin/sh
foo=bar
$ ./test.sh
$ echo $foo

$ . ./test.sh
$ echo $foo
bar

17
การเพิ่มecho $$ไปยังสคริปต์จะแสดงความแตกต่างค่อนข้างชัดเจน $$ตัวแปรถือ PID ของเปลือกปัจจุบัน

1
สถานการณ์การใช้งานอื่นคือการใช้การ. ./test.shโทรจากภายในเชลล์สคริปต์อื่นเพื่อใช้ฟังก์ชั่นที่อธิบายไว้ใน test.sh ฉันหมายความว่ามันไม่ได้เป็นเพียงตัวแปรที่คุณสามารถตั้งค่าได้ แต่คุณยังสามารถสร้างฟังก์ชั่นใหม่ด้วยวิธีนี้ซึ่งจะเรียกได้จากการทุบตีหรือสคริปต์อื่น ๆ . /usr/libexec/company/tools; custom_command "variable"
Rqomey

9

การเรียกใช้สคริปต์วิธีแรกจะเรียกใช้เป็นกระบวนการลูก ในทางกลับกันการจัดหา (ทางที่สอง) เรียกใช้สคริปต์ราวกับว่าคุณป้อนคำสั่งทั้งหมดลงในเชลล์ปัจจุบัน - หากสคริปต์ตั้งค่าตัวแปรมันจะยังคงตั้งค่าหากสคริปต์ออกจากเซสชันของคุณจะออก ดูhelp .เอกสารประกอบ


3

อีกสิ่งที่ฉันทราบคือถ้าคุณมีนามแฝงเช่นนี้:

# add into .bashrc_aliases
alias ls='ls -lht'

ด้วย./test.shคุณจะได้รับlsเอาต์พุตปกติ(และ PID ที่แตกต่างจากเชลล์ปัจจุบัน):

auraham@pandora:~/iso$ ./test.sh 
dsl-4.4.10.iso  test.sh
3136 # PID

ด้วย. test.shหรือ. ./test.shคุณจะได้รับผลลัพธ์ที่มีรายละเอียดมากขึ้น (และ PID เดียวกันมากกว่าเชลล์ปัจจุบัน):

auraham@pandora:~/iso$ echo $$
2767 # shell PID

auraham@pandora:~/iso$ . test.sh 
total 50M
drwxrwxr-x  2 auraham auraham 4.0K Jul 30 15:41 .
-rwxrwxr-x  1 auraham auraham   32 Jul 30 15:41 test.sh
drwxr-xr-x 50 auraham auraham 4.0K Jul 30 15:30 ..
-rw-rw-r--  1 auraham auraham  50M Jul 28 17:24 dsl-4.4.10.iso
2767 # PID

คุณสามารถรวมในนั้นก็ให้ใส่ชื่อแทนของคุณ.bashrc if [ -f ~/.bash_aliases ]; then . ~/.bash_aliases fi .bash_aliases
auraham

แน่นอน แต่คุณไม่จำเป็นต้องใช้aliasคำหลักเหรอ? (อาจเป็นเพียงความผิดพลาดในคุณโพสต์ - บนบรรทัดที่ 3?)
Emanuel Berg

ถูกต้องทั้งหมดความผิดพลาดของฉัน ขอบคุณ @EmanuelBerg
auraham

-1

การใช้งานหลักในการฉันสำหรับsource(หรือ.) เป็นฟังก์ชั่นการทุบตี

.bashrcฉันมีสคริปต์ที่มีฟังก์ชั่นจำนวนมากและผมดำเนินการทั้งหมดของพวกเขากับฉัน คำสั่งฟังก์ชั่น "กลายเป็น" ซึ่งฉันใช้บ่อยๆ


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