Unix: В чем разница между источником и экспортом?
Я пишу сценарий оболочки, чтобы прочитать файл с парой ключ = значение и установить эти переменные в качестве переменных среды. Но у меня есть сомнения, если я сделаю source file.txt
это установит переменные, определенные в этом файле, как переменную среды, или я должен прочитать файл построчно и установить его с помощью команды экспорта?
В этом случае команда источника отличается от экспорта?
1 ответ
Когда ты source
файл, назначения будут установлены как переменные, но не как переменные среды, если только allexport
опция была установлена. Если вы хотите, чтобы переменные помещались в окружение, использовать их гораздо проще allexport
а также source
файл, чем это, чтобы прочитать файл и использовать export
в явном виде. Другими словами, вы должны сделать:
set -a
. file.txt
(Я предпочитаю .
потому что это более портативный, чем source
, но source
прекрасно работает в bash
.)
source
(.
) против export
(а также некоторая блокировка файла [flock
] в конце):
Короче говоря:
source some_script.sh
или эквивалент, совместимый с POSIX,. some_script.sh
, переносит переменные из других скриптов, аexport my_var="something"
выталкивает переменные в другие сценарии / процессы, которые вызываются / запускаются из текущего сценария / процесса.
С помощью source some_script.sh
или . some_script.sh
в сценарии оболочки Linux это похоже на использование import some_module
в Python или #include <some_header_file.h>
на C или C++. Он вводит переменные из исходного сценария.
С помощью export some_var="something"
это что-то вроде установки этой переменной локально, поэтому она доступна для остальной части текущего скрипта или процесса, а затем также передает ее во все подпрограммы или процессы, которые вы можете вызывать с этого момента.
Подробнее:
Итак, это:
# export `some_var` so that it is set and available in the current script/process,
# as well as in all sub-scripts or processes which are called from the
# current script/process
export some_var="something"
# call other scripts/processes, passing in `some_var` to them automatically
# since it was just exported above!
script1.sh # this script now gets direct access to `some_var`
script2.sh # as does this one
script3.sh # and this one
это как если бы вы сделали это:
# set this variable for the current script/process only
some_var="something"
# call other scripts/processes, passing in `some_var` to them **manually**
# so they can use it too
some_var="something" script1.sh # manually pass in `some_var` to this script
some_var="something" script2.sh # manually pass in `some_var` to this script
some_var="something" script3.sh # manually pass in `some_var` to this script
за исключением того, что первая версия выше, где мы вызвали export some_var="something"
на самом деле имеет рекурсивную передачу или экспорт переменных в подпроцессы, поэтому, если мы вызываем script1.sh
изнутри нашего текущего скрипта / процесса, затем script1.sh
получит экспортированные переменные из нашего текущего скрипта, и если script1.sh
звонки script5.sh
, а также script5.sh
звонки script10.sh
, то оба этих сценария автоматически получат экспортированные переменные. Это отличается от приведенного выше ручного случая, когда только те сценарии, которые явно вызываются с вручную установленными переменными при вызове сценариев, получат их, поэтому подпрограммы НЕ будут автоматически получать какие-либо переменные из своих вызывающих сценариев!
Как "отменить экспорт" переменной:
Обратите внимание, что после экспорта переменной вызов unset
на нем будет "экспортировать его", вот так:
# set and export `some_var` so that sub-processes will receive it
export some_var="something"
script1.sh # this script automatically receives `some_var`
# unset and un-export `some_var` so that sub-processes will no longer receive it
unset some_var
script1.sh # this script does NOT automatically receive `some_var`
В итоге:
source
или.
импорт.export
экспорт.unset
экспорт.
Пример:
Создайте этот скрипт:
source_and_export.sh:
#!/bin/bash
echo "var1 = $var1"
var2="world"
Затем отметьте его исполняемым:
chmod +x source_and_export.sh
Теперь я запускаю несколько команд в терминале, чтобы проверить source
(.
) а также export
команды с этим скриптом. Введите команду, которую вы видите после строк, начинающихся с$
(не считая комментариев). Остальные строки - это результат. Выполните команды последовательно, по одной команде за раз:
$ echo "$var1" # var1 contains nothing locally
$ var1="hello" # set var1 to something in the current process only
$ ./source_and_export.sh # call a sub-process
var1 = # the sub-process can't see what I just set var1 to
$ export var1 # **export** var1 so sub-processes will receive it
$ ./source_and_export.sh # call a sub-process
var1 = hello # now the sub-process sees what I previously set var1 to
$ echo "$var1 $var2" # but I can't see var2 from the subprocess/subscript
hello
$ . ./source_and_export.sh # **source** the sub-script to _import_ its var2 into the current process
var1 = hello
$ echo "$var1 $var2" # now I CAN see what the subprocess set var2 to because I **sourced it!**
hello world # BOTH var1 from the current process and var2 from the sub-process print in the current process!
$ unset var1 # unexport (`unset`) var1
$ echo "$var1" # var1 is now NOT set in the current process
$ ./source_and_export.sh # and the sub-process doesn't receive it either
var1 =
$ var1="hey" # set var1 again in the current process
$ . ./source_and_export.sh # if I **source** the script, it runs in the current process, so it CAN see var1 from the current process!
var1 = hey # notice it prints
$ ./source_and_export.sh # but if I run the script as a sub-process, it can NOT see var1 now because it was `unset` (unexported)
var1 = # above and has NOT been `export`ed again since then!
$
Использование файлов как глобальных переменных
Иногда при написании скриптов для запуска программ и прочего я встречал случаи, когда export
похоже, не работает правильно. В этих случаях иногда приходится прибегать к использованию самих файлов в качестве глобальных переменных для передачи информации от одной программы к другой. Вот как это можно сделать. В этом примере существование файла "~/temp/.do_something" функционирует как межпроцессная логическая переменная:
# In program A, if the file "~/temp/.do_something" does NOT exist,
# then create it
mkdir -p ~/temp
if [ ! -f ~/temp/.do_something ]; then
touch ~/temp/.do_something # create the file
fi
# In program B, check to see if the file exists, and act accordingly
mkdir -p ~/temp
DO_SOMETHING="false"
if [ -f ~/temp/.do_something ]; then
DO_SOMETHING="true"
fi
if [ "$DO_SOMETHING" == "true" ] && [ "$SOME_OTHER_VAR" == "whatever" ]; then
# remove this global file "variable" so we don't act on it again
# until "program A" is called again and re-creates the file
rm ~/temp/.do_something
do_something
else
do_something_else
fi
Простая проверка существования файла, как показано выше, отлично подходит для глобальной передачи логических условий между программами и процессами. Однако, если вам нужно передать более сложные переменные, такие как строки или числа, вам может потребоваться сделать это, записав эти значения в файл. В таких случаях следует использовать функцию блокировки файла,flock
, чтобы правильно обеспечить межпроцессную синхронизацию. Это тип безопасного для процесса (т.е. "межпроцессного") примитива мьютекса. Вы можете прочитать об этом здесь:
- Сценарий оболочки
flock
команда: https://man7.org/linux/man-pages/man1/flock.1.html. Смотрите такжеman flock
илиman 1 flock
. - Команда библиотеки Linux C: https://man7.org/linux/man-pages/man2/flock.2.html. Смотрите также
man 2 flock
. Вы должны#include <sys/file.h>
в вашем файле C, чтобы использовать эту функцию.
Ссылки:
- https://askubuntu.com/questions/862236/source-vs-export-vs-export-ld-library-path/862256
- Мои собственные эксперименты и испытания
- Я добавлю приведенный выше пример в свой проект на GitHub здесь, под
bash
папка: https://github.com/ElectricRCAircraftGuy/eRCaGuy_hello_world