เหตุใดแหล่งที่มา lib / * จึงไม่ทำงาน


11

ฉันมีโปรแกรมขนาดเล็กซึ่งมีโครงสร้างโฟลเดอร์ต่อไปนี้:

- main.sh
- lib/
  - clean.sh
  - get.sh
  - index.sh
  - test.sh

main.shแต่ละไฟล์ที่มีฟังก์ชั่นเดียวที่ผมใช้ใน

main.sh:

source lib/*

get_products
clean_products
make_index
test_index

ในสองฟังก์ชันแรกด้านบนทำงานได้ แต่ฟังก์ชันที่สองไม่ทำงาน

แต่ถ้าฉันแทนที่source lib/*ด้วย:

source lib/get.sh
source lib/clean.sh
source lib/index.sh
source lib/test.sh

ทุกอย่างทำงานตามที่คาดไว้

ใครรู้ว่าทำไมsource lib/*ไม่ทำงานตามที่คาดไว้


2
ไม่ตอบคำถามหากคุณต้องการทำแบบหนึ่งซับให้ดู/etc/bashrcว่ามันใช้forลูปในการจัดการ/etc/profile.d/*.shอย่างไร หากคุณเชื่อว่าเนื้อหาของlib/มันสามารถลดลงหนึ่งซับ:for i in lib/*.sh; do . "$i"; done
รวย

คำตอบ:


21

บิวด์อินของ Bash sourceใช้ชื่อไฟล์เดียวเท่านั้น:

source filename [arguments]

filenameสิ่งใดเกินพารามิเตอร์แรกกลายเป็นพารามิเตอร์ตำแหน่งไป

ภาพประกอบง่าย ๆ :

$ cat myfile
echo "param1: $1"
$ source myfile foo
param1: foo

ผลผลิตเต็มรูปแบบของ help source

source: source filename [arguments]

Execute commands from a file in the current shell.

Read and execute commands from FILENAME in the current shell.  The
entries in $PATH are used to find the directory containing FILENAME.
If any ARGUMENTS are supplied, they become the positional parameters
when FILENAME is executed.

Exit Status:
Returns the status of the last command executed in FILENAME; fails if
FILENAME cannot be read.

(สิ่งนี้ยังนำไปใช้กับ "จุดแหล่งที่มา" ในตัว.ซึ่งมันก็น่าสังเกตว่าเป็นวิธี POSIX และพกพามากขึ้น)

สำหรับพฤติกรรมที่ดูเหมือนจะขัดแย้งที่คุณเห็นคุณสามารถลองใช้ main.sh set -xหลังจากที่ทำ ดูว่างบใดบ้างที่ถูกเรียกใช้และเมื่อใดที่อาจให้เบาะแส


7

เอกสาร Bashระบุว่าใช้sourceงานได้กับชื่อไฟล์เดียว:

. (ช่วงเวลา)

. ชื่อไฟล์ [อาร์กิวเมนต์]

อ่านและดำเนินการคำสั่งจากอาร์กิวเมนต์ชื่อไฟล์ในบริบทเชลล์ปัจจุบัน หากชื่อไฟล์ ...

และซอร์สโค้ด ... สำหรับซอร์ส ... สำรองข้อมูลนี้:

result = source_file (filename, (list && list->next));

ในกรณีที่source_fileถูกกำหนดไว้ในevalfile.cการเรียก_evalfile:

rval = _evalfile (filename, flags);

และ_evalfileเปิดไฟล์เดียวเท่านั้น:

fd = open (filename, O_RDONLY);

5

การเติมเต็มคำตอบที่เป็นประโยชน์ของ b-layerฉันขอแนะนำว่าอย่าใช้การขยายแบบโลภหากคุณไม่แน่ใจว่ามีไฟล์ประเภทที่พยายามขยายอยู่หรือไม่

เมื่อคุณทำด้านล่างมีความเป็นไปได้ของไฟล์ (ไม่มี.shนามสกุล) เพียงไฟล์ชั่วคราวที่มีคำสั่งที่เป็นอันตราย (เช่นrm -rf *) ซึ่งสามารถดำเนินการได้ (สมมติว่าพวกเขามีสิทธิ์ดำเนินการ)

source lib/*

ในกรณีของคุณแม้ว่าคุณจะสามารถวน*.shไฟล์ได้ตามลำพัง

for globFile in lib/*.sh; do
    [ -f "$globFile" ] || continue
    source "$globFile"
done

ที่นี่[ -f "$globFile" ] || continueจะดูแลการย้อนกลับออกจากลูปหากไม่มีรูปแบบกลมตรงในโฟลเดอร์ปัจจุบันเช่นเทียบเท่ากับตัวเลือกเปลือกขยายnullglobในbashเปลือก


การใช้การทดแทนกระบวนการด้วยcatอาจใช้งานได้:source <(cat lib/*.sh)
Xophmeister

@Xophmeister, ... สำหรับค่าที่ จำกัด มากขึ้นสำหรับ "งาน" หากคุณพยายามที่จะแก้ปัญหาด้วยset -xและPS4ที่ทำให้BASH_SOURCEและLINENOในบันทึกของคุณคุณไม่สามารถดูไฟล์และบรรทัดคำสั่งที่กำหนดมาจาก
Charles Duffy

2
@ Xophmeister, ... และสคริปต์สามารถตัดการใช้งานของมันให้สั้นreturnลงได้ จากการปฏิบัติดังกล่าวสคริปต์ใด ๆ ที่ทำเพื่อป้องกันไม่ให้ผู้ที่ติดตามอยู่ดำเนินการ
Charles Duffy

1
นี้อยู่ใกล้สวยวิธีการที่จะทำในเมื่อมันประมวลผล/etc/bashrc /etc/profile.d/*.sh
รวย

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