เลือกระหว่าง $ 0 ถึง BASH_SOURCE


120

วิธีการเลือกระหว่าง"$0"และ"${BASH_SOURCE[0]}"

คำอธิบายจากGNUนี้ไม่ได้ช่วยอะไรฉันมากนัก

    BASH_SOURCE

 An array variable whose members are the source filenames where the
 corresponding shell function names in the FUNCNAME array variable are
 defined. The shell function ${FUNCNAME[$i]} is defined in the file
 ${BASH_SOURCE[$i]} and called from ${BASH_SOURCE[$i+1]}

BASH_SOURCEถูกเพิ่มที่ bash-3.0-alpha คุณอาจไม่มีขึ้นอยู่กับระบบการทดสอบของคุณ ฉันพบว่ามันหายไปทั้งใน Solaris และ OS X รุ่นแรกดูผลตอบแทน: สามารถ `` ย้อนกลับ 'จากฟังก์ชันหรือสคริปต์ที่มาใน U & L.SE เท่านั้น
jww

คำตอบ:


174

หมายเหตุ: สำหรับโซลูชันที่สอดคล้องกับ POSIX โปรดดูคำตอบนี้

${BASH_SOURCE[0]}(หรือเพิ่มเติมเพียง$BASH_SOURCE[1] ) มี (อาจญาติ) เส้นทางของสคริปต์ที่มีในทุกสถานการณ์การภาวนาสะดุดตาเมื่อสคริปต์มา$0ซึ่งไม่เป็นความจริงสำหรับ

นอกจากนี้ดังที่Charles Duffyชี้ให้เห็นว่าผู้โทร$0สามารถตั้งค่าตามอำเภอใจได้
ในด้านพลิก$BASH_SOURCE สามารถว่างได้หากไม่มีไฟล์ที่มีชื่อเกี่ยวข้อง เช่น:
echo 'echo "[$BASH_SOURCE]"' | bash

ตัวอย่างต่อไปนี้แสดงให้เห็นสิ่งนี้:

สคริปต์foo:

#!/bin/bash
echo "[$0] vs. [${BASH_SOURCE[0]}]"

$ bash ./foo
[./foo] vs. [./foo]

$ ./foo
[./foo] vs. [./foo]

$ . ./foo
[bash] vs. [./foo]

$0เป็นส่วนหนึ่งของข้อกำหนดเชลล์ POSIX ในขณะBASH_SOURCEที่ชื่อแนะนำเป็นเฉพาะ Bash


[1] การอ่านเพิ่มเติม: ${BASH_SOURCE[0]}เทียบกับ$BASH_SOURCE :

Bash ช่วยให้คุณสามารถอ้างอิงองค์ประกอบ0ของตัวแปรอาร์เรย์โดยใช้สัญกรณ์สเกลาร์ : แทนที่จะเขียน${arr[0]}คุณสามารถเขียน$arr; ในคำอื่น ๆ ถ้าคุณอ้างอิงตัวแปรราวกับว่ามันเป็นสเกลา0คุณจะได้รับองค์ประกอบที่ดัชนี

การใช้คุณสมบัตินี้บดบังความจริงที่ว่า$arrคืออาร์เรย์ซึ่งเป็นเหตุผลว่าทำไมลินเตอร์โค้ดเชลล์ที่เป็นที่นิยมshellcheck.net จึงออกคำเตือนต่อไปนี้ (ณ การเขียนนี้):

SC2128: การขยายอาร์เรย์โดยไม่มีดัชนีจะให้องค์ประกอบแรกเท่านั้น

หมายเหตุด้านข้าง: แม้ว่าคำเตือนนี้จะมีประโยชน์ แต่ก็อาจมีความแม่นยำมากขึ้นเนื่องจากคุณไม่จำเป็นต้องได้รับองค์ประกอบแรก : โดยเฉพาะองค์ประกอบที่ดัชนี0ที่ส่งกลับดังนั้นหากองค์ประกอบแรกมีดัชนีสูงกว่าซึ่ง เป็นไปได้ใน Bash - คุณจะได้รับสตริงว่าง ลอง'a[1]='hi'; echo "$a"'.
(ในทางตรงกันข้ามzshผู้ทรยศจะส่งกลับองค์ประกอบแรกโดยไม่คำนึงถึงดัชนีของมัน)

คุณอาจเลือกที่จะหลบหนีคุณลักษณะนี้เนื่องจากความสับสนของมัน แต่มันทำงานไม่คาดฝันและจริงจังพูดคุณจะไม่ค่อยหากเคยจำเป็นต้องดัชนีการเข้าถึงอื่น ๆกว่าของตัวแปรอาร์เรย์0${BASH_SOURCE[@]}


ดังนั้น $ BASH_SOURCE จึงเป็นแบบทั่วไปและใช้งานได้ในหลาย ๆ สถานการณ์?
Alexander Mills

2
@AlexanderMills ใช่ถ้าคุณใช้ Bash $BASH_SOURCEเป็นทางเลือกที่ดีกว่า
mklement0

19

สคริปต์เหล่านี้อาจช่วยอธิบายได้ สคริปต์ภายนอกเรียกสคริปต์กลางซึ่งเรียกสคริปต์ภายใน:

$ cat outer.sh
#!/usr/bin/env bash
./middle.sh
$ cat middle.sh
#!/usr/bin/env bash
./inner.sh
$ cat inner.sh
#!/usr/bin/env bash
echo "\$0 = '$0'"
echo "\${BASH_SOURCE[0]} = '${BASH_SOURCE[0]}'"
echo "\${BASH_SOURCE[1]} = '${BASH_SOURCE[1]}'"
echo "\${BASH_SOURCE[2]} = '${BASH_SOURCE[2]}'"
$ ./outer.sh
$0 = './inner.sh'
$BASH_SOURCE[0] = './inner.sh'
$BASH_SOURCE[1] = ''
$BASH_SOURCE[2] = ''

อย่างไรก็ตามหากเราเปลี่ยนการเรียกสคริปต์เป็นsourceคำสั่ง:

$ cat outer.sh
#!/usr/bin/env bash
source ./middle.sh
$ cat middle.sh
#!/usr/bin/env bash
source ./inner.sh
$ cat inner.sh
#!/usr/bin/env bash
echo "\$0 = '$0'"
echo "\${BASH_SOURCE[0]} = '${BASH_SOURCE[0]}'"
echo "\${BASH_SOURCE[1]} = '${BASH_SOURCE[1]}'"
echo "\${BASH_SOURCE[2]} = '${BASH_SOURCE[2]}'"
$ ./outer.sh
$0 = './outer.sh'
$BASH_SOURCE[0] = './inner.sh'
$BASH_SOURCE[1] = './middle.sh'
$BASH_SOURCE[2] = './outer.sh'

1

สำหรับการพกพาให้ใช้${BASH_SOURCE[0]}เมื่อมีการกำหนดไว้และ$0อื่น ๆ ที่ให้

${BASH_SOURCE[0]:-$0}

โดยเฉพาะอย่างยิ่งใน zsh $ 0 มี filepath ที่ถูกต้องแม้ว่าสคริปต์จะเป็นsourced ก็ตาม

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