У меня есть небольшая программа, которая содержит следующую структуру папок:
- 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/*
не работает, как ожидалось?
/etc/bashrc
как он используетfor
цикл для решения/etc/profile.d/*.sh
. Если вы доверяете содержимому,lib/
его можно сократить до однострочного:for i in lib/*.sh; do . "$i"; done
Ответы:
Встроенный Bash
source
принимает только одно имя файла:Все, что находится за пределами первого параметра, становится позиционным параметром для
filename
.Простая иллюстрация:
Полный вывод
help source
(Это также относится к эквивалентному встроенному «точечному источнику»,
.
который, стоит отметить, является способом POSIX и, следовательно, более переносимым.)Что касается кажущегося противоречивого поведения, которое вы видите, вы можете попробовать запустить main.sh после выполнения
set -x
. Видеть, какие операторы выполняются и когда могут дать подсказку.источник
Bash документация указывает, что
source
работает с одним именем файла :И исходный код ... для источника ... подтверждает это:
Где
source_file
определено вevalfile.c
звонить_evalfile
:и
_evalfile
открывает только один файл:источник
В дополнение к полезному ответу b-layer , я бы посоветовал никогда не использовать жадное расширение glob, если вы не уверены, существуют ли файлы типа, пытающегося раскрыться.
Когда вы сделали это ниже, существует вероятность того, что файл (не имеющий
.sh
расширения) будет просто временным файлом, содержащим некоторые вредоносные команды (напримерrm -rf *
), которые могут быть выполнены (при условии, что у них есть разрешения на выполнение)Так что всегда делайте расширение glob с правильным набором границ, в вашем случае, хотя вы можете просто зацикливаться только на
*.sh
файлахЗдесь
[ -f "$globFile" ] || continue
он позаботится о возврате из цикла, если в текущей папке не найден шаблон глобуса, то есть эквивалент расширенных параметров оболочкиnullglob
вbash
оболочке.источник
cat
также будет работать:source <(cat lib/*.sh)
set -x
и a,PS4
который помещаетBASH_SOURCE
иLINENO
в ваши журналы, вы больше не видите, из какого файла и строки дается данная команда.return
. Следуя этой практике, любой скрипт, который делает это, будет препятствовать выполнению всех следующих./etc/bashrc
при обработке/etc/profile.d/*.sh
.source
требуется только разрешение на чтение, а не выполнение