
У меня есть 2 скрипта оболочки, file1.sh и file2.sh
файл1.sh
#!/usr/bin/env bash
export var1="/data/share"
export var2='password'
echo "Hello"
файл2.sh
#!/usr/bin/env bash
source file1.sh
echo $var1
echo $var2
Когда я запускаю file2.sh, я получаю следующий вывод
Hello
/data/share
password
Но мой ожидаемый результат:
/data/share
password
file1.sh выполняется при ссылке в file2.sh. Как импортировать только переменные в file2.sh без выполнения file1.sh?
решение1
Есть три варианта, которые я использую, когда у меня есть скрипт bash, который я хочу вести себя по-разному при его вызове и при его выполнении (или, другими словами, иметь элементы данных в скрипте, к которым я хочу получить доступ без выполнения какого-либо кода в это время). Комментарии в некоторой степени затронули их.
Вариант первый
Определите, когда осуществляется закупка, и завершите «закупку» в подходящее время
Разделите скрипт на две части, выйдите из скрипта, если он получен, прежде чем перейти к нижней второй части
Создайте верхнюю часть скрипта с определениями (функции/назначения переменных и т. д.), но без прямого выполнения кода.
Перед началом раздела исполняемого кода поместите логику, которая завершит выполнение скрипта, если он обнаружит, что он находится в режиме source. Следующий сегмент кода сделает это:
файл1.sh
#!/usr/bin/env bash
export var1="/data/share"
export var2='password'
# --- End Definitions Section ---
# check if we are being sourced by another script or shell
[[ "${#BASH_SOURCE[@]}" -gt "1" ]] && { return 0; }
# --- Begin Code Execution Section ---
echo "Hello"
echo $var1
echo $var2
файл2.sh
#!/usr/bin/env bash
source file1.sh
echo "$var1"
echo "$var2"
Вывод запуска ./file2.sh
$ ./file2.sh
/data/share
password
Вариант два
Этот режим обычно используется только в сложных ситуациях, и для этого конкретного примера он излишен. Я создаю функцию в файле, который хочу использовать в качестве источника, и в этой функции определяю, что должно быть доступно вызывающему. В данном случае это две экспортированные переменные. Обычно я использую этот режим, когда у меня есть ассоциативные массивы, которые в противном случае практически невозможно обработать. Кроме того, файл tmp должен быть удален вызывающим; но в этом случае я этого не сделал:
файл1.sh
#!/usr/bin/env bash
export var1="/data/share"
export var2='password'
exportCfg() {
tmpF=$(mktemp)
declare -p var1 var2 > "$tmpF"
echo "$tmpF"
}
if [ "$1" == "export" ]; then
exportCfg;
exit 0;
fi
echo "Hello"
echo $var1
echo $var2
файл2.sh
#!/usr/bin/env bash
source $(./file1.sh export)
echo "$var1"
echo "$var2"
Вывод от выполнения file2.sh такой же, как и выше.
Вариант 3
Последний распространенный способ, которым я справляюсь с этим, — это просто файл библиотеки, который содержит только определения и не имеет кода, который будет выполняться при получении или прямом запуске. Это просто вопрос разделения вашего кода. У меня есть группа bash 'libs', которые содержат часто используемые функции, и на основе каждого проекта я обычно настраиваю небольшую библиотеку с исходным кодом для хранения данных конфигурации (констант). Если эти данные включают заполненные массивы, то я также буду использовать версию Варианта 2.
решение2
Если все ваши переменные экспортируются одинаково (экспортировать foo=bar), то вы можете легко получить их все, используяБашФункция замены процесса:
source <(grep '^export .*=' file1.sh)
Выдержка из страницы руководства:
Подстановка процессов Подстановка процессов поддерживается в системах, которые поддерживают именованные каналы (FIFO) или метод именования открытых файлов /dev/fd. Он принимает форму <(list) или >(list). Список процессов запускается с его входом или выходом, подключенным к FIFO или некоторому файлу в /dev/fd. Имя этого файла передается в качестве аргумента текущей команде в результате расширения. Если используется форма >(list), запись в файл предоставит входные данные для списка. Если используется форма <(list), файл, переданный в качестве аргумента, должен быть прочитан для получения вывода списка.