Передавать все переменные из одного shellscript в другой?
Итак, скажем, у меня есть shellscript/ bash script с именем test.sh
с:
#!/bin/bash
#
TESTVARIABLE=hellohelloheloo
./test2.sh
my test2.sh выглядит следующим образом
#!/bin/bash
#
echo ${TESTVARIABLE}
это не работает. Я не хочу передавать все переменные в качестве параметров, так как imho это перебор. Есть ли другой способ?
Ответы
Ответ 1
У вас есть в основном два варианта:
- Внесите переменную переменную среды (
export TESTVARIABLE
) перед выполнением второго script.
- Источник 2-го script, т.е.
. test2.sh
, и он будет работать в той же оболочке. Это позволит вам легко делиться более сложными переменными, такими как массивы, но также означает, что другой script может изменять переменные в исходной оболочке.
UPDATE:
Чтобы использовать export
для установки переменной среды, вы можете либо использовать существующую переменную:
A=10
# ...
export A
Это должно работать как в bash
, так и в sh
. bash
также позволяет комбинировать его так:
export A=10
Это также работает в моем sh
(что бывает bash
, вы можете использовать echo $SHELL
для проверки). Но я не верю, что это гарантировано для работы во всех sh
, поэтому лучше всего безопасно и отделить их.
Любая экспортируемая вами переменная будет видна в исполняемых сценариях, например:
a.sh:
#!/bin/sh
MESSAGE="hello"
export MESSAGE
./b.sh
b.sh:
#!/bin/sh
echo "The message is: $MESSAGE"
Тогда:
$ ./a.sh
The message is: hello
Тот факт, что это оба сценария оболочки, также является случайным. Переменные окружения могут быть переданы любому процессу, который вы выполняете, например, если мы использовали python, это может выглядеть так:
a.sh:
#!/bin/sh
MESSAGE="hello"
export MESSAGE
./b.py
b.py:
#!/usr/bin/python
import os
print 'The message is:', os.environ['MESSAGE']
Sourcing:
Вместо этого мы могли бы так выглядеть:
a.sh:
#!/bin/sh
MESSAGE="hello"
. ./b.sh
b.sh:
#!/bin/sh
echo "The message is: $MESSAGE"
Тогда:
$ ./a.sh
The message is: hello
Это более или менее "импортирует" содержимое b.sh
напрямую и выполняет его в той же оболочке. Обратите внимание, что нам не нужно было экспортировать переменную для доступа к ней. Это неявно разделяет все переменные, которые у вас есть, а также позволяет другому script добавлять/удалять/изменять переменные в оболочке. Конечно, в этой модели оба ваших сценария должны быть одного языка (sh
или bash
). Чтобы привести пример, как мы могли передавать сообщения взад и вперед:
a.sh:
#!/bin/sh
MESSAGE="hello"
. ./b.sh
echo "[A] The message is: $MESSAGE"
b.sh:
#!/bin/sh
echo "[B] The message is: $MESSAGE"
MESSAGE="goodbye"
Тогда:
$ ./a.sh
[B] The message is: hello
[A] The message is: goodbye
Это одинаково хорошо работает в bash
. Он также позволяет легко делиться более сложными данными, которые вы не могли бы выразить как переменную среды (по крайней мере, без какого-либо тяжелого подъема с вашей стороны), например массивы или ассоциативные массивы.
Ответ 2
Fatal Error предоставила прямую возможность: отправьте второй script! если вы опасаетесь, что этот второй script может изменить некоторые ваши драгоценные переменные, вы всегда можете указать его в подоболочке:
( . ./test2.sh )
Скобки заключают, что источник происходит в подоболочке, так что родительская оболочка не увидит изменений test2.sh
.
Здесь также может быть указана другая возможность: используйте set -a
.
В POSIX set
ссылка:
-a
: если этот параметр включен, атрибут экспорта должен быть установлен для каждой переменной, которой выполняется присвоение; см. раздел "Базовые определения" IEEE Std 1003.1-2001, Раздел 4.21 "Назначение переменных" . Если присваивание предшествует имени утилиты в команде, атрибут экспорта не должен сохраняться в текущей среде исполнения после завершения работы утилиты, за исключением того, что предшествующий одной из специальных встроенных утилит заставляет атрибут экспорта сохраняться после того, в завершена. Если присваивание не предшествует имени утилиты в команде или если задание является результатом работы утилит getopts или read, атрибут экспорта сохраняется до тех пор, пока переменная не будет отменена.
В Bash Руководстве:
-a
: Отметьте переменные и функцию, которые были изменены или созданы для экспорта в среду последующих команд.
Итак, в вашем случае:
set -a
TESTVARIABLE=hellohelloheloo
# ...
# Here put all the variables that will be marked for export
# and that will be available from within test2 (and all other commands).
# If test2 modifies the variables, the modifications will never be
# seen in the present script!
set +a
./test2.sh
# Here, even if test2 modifies TESTVARIABLE, you'll still have
# TESTVARIABLE=hellohelloheloo
Обратите внимание, что в спецификациях указывается только, что при set -a
переменная отмечена для экспорта. То есть:
set -a
a=b
set +a
a=c
bash -c 'echo "$a"'
будет echo c
, а не пустая строка, а b
(т.е. set +a
не отменит экспорт для экспорта и не сохранит значение присваивания только для экспортируемой среды). Это, конечно, самое естественное поведение.
Заключение: использование set -a
/set +a
может быть менее утомительным, чем экспорт вручную всех переменных. Он превосходит поиск второго script, поскольку он будет работать для любой команды, а не только тех, которые написаны на одном языке.
Ответ 3
На самом деле более простой путь, чем экспорт и отключение или поиск ресурсов (по крайней мере, в bash, если вы в порядке с передачей переменных среды вручную):
пусть a.sh be
#!/bin/bash
secret="winkle my tinkle"
echo Yo, lemme tell you \"$secret\", b.sh!
Message=$secret ./b.sh
и b.sh be
#!/bin/bash
echo I heard \"$Message\", yo
Наблюдаемый выход
[rob @Archie test] $./a.sh
Эй, лемм, скажи, что ты "подмигиваешь моему звонку", b.sh!
Я услышал "подмигиваю мой звон", лет
Магия лежит в последней строке a.sh
, где Message
, для только продолжительности вызова ./b.sh
, устанавливается значение secret
из a.sh
.
В принципе, это немного похоже на именованные параметры/аргументы. Более того, он работает даже с такими переменными, как $DISPLAY
, который управляет запуском приложения X Server.
Помните, что длина списка переменных окружения не бесконечна. В моей системе с относительно ванильным ядром xargs --show-limits
говорит, что максимальный размер буфера аргументов составляет 2094486 байт. Теоретически, вы используете сценарии оболочки неправильно, если ваши данные больше, чем это (трубы, кто-нибудь?)
Ответ 4
Добавление к ответу Fatal Error, есть еще один способ передать переменные в другую оболочку script.
Вышеупомянутое предлагаемое решение имеет некоторые недостатки:
-
using Export
: это приведет к тому, что переменная будет присутствовать вне их области действия, что не является хорошей практикой проектирования.
-
using Source
. Это может вызвать конфликты имен или случайную перезапись предопределенной переменной в каком-то другом файле оболочки script, в котором есть другой файл.
Существует еще одно простое решение, которое мы можем использовать.
Учитывая пример, опубликованный вами,
test.sh
#!/bin/bash
TESTVARIABLE=hellohelloheloo
./test2.sh "$TESTVARIABLE"
test2.sh
#!/bin/bash
echo $1
вывод
hellohelloheloo
Также важно отметить, что ""
необходимы, если мы передаем многословные строки.
Еще один пример
master.sh
#!/bin/bash
echo in master.sh
var1="hello world"
sh slave1.sh $var1
sh slave2.sh "$var1"
echo back to master
slave1.sh
#!/bin/bash
echo in slave1.sh
echo value :$1
slave2.sh
#!/bin/bash
echo in slave2.sh
echo value : $1
Выход
in master.sh
in slave1.sh
value :"hello
in slave2.sh
value :"hello world"
Это происходит из-за причин, которые точно описаны в этой ссылке
Ответ 5
В Bash, если вы экспортируете переменную внутри подоболочки, используя скобки, как показано, вы избегаете утечки экспортированных переменных:
#!/bin/bash
TESTVARIABLE=hellohelloheloo
(
export TESTVARIABLE
source ./test2.sh
)
Преимущество заключается в том, что после запуска script из командной строки вы не увидите пропущенную в вашей среде $TESTVARIABLE:
$ ./test.sh
hellohelloheloo
$ echo $TESTVARIABLE
#empty! no leak
$
Ответ 6
Другим способом, который немного легче для меня, является использование именованных каналов. Именованные каналы обеспечивают способ синхронизации и отправки сообщений между различными процессами.
A.bash:
#!/bin/bash
msg="The Message"
echo $msg > A.pipe
B.bash:
#!/bin/bash
msg=`cat ./A.pipe`
echo "message from A : $msg"
Использование:
$ mkfifo A.pipe #You have to create it once
$ ./A.bash & ./B.bash # you have to run your scripts at the same time
B.bash будет ждать сообщения, и как только A.bash отправит сообщение, B.bash продолжит работу.
Ответ 7
Другой вариант - использование eval
. Это подходит только тогда, когда строки доверяют. Первый script может повторять назначение переменных:
echo "VAR=myvalue"
Тогда:
eval $(./first.sh) ./second.sh
Этот подход представляет особый интерес, когда второй script, который вы хотите установить для переменных окружения, находится не в bash, и вы также не хотите, чтобы переменные export
, возможно, потому, что они чувствительны, и вы не Не хочу, чтобы они сохранялись.