В линукс-системах, в консоли, каждый скрипт запускается следующим образом:
1) определяется необходимый интерпретатор для его выполнения (на основе указания-подсказки внутри самого файла, по расширению, и т.п.)
2) запускается новый процесс командного интерпретатора, в рамках которого и выполняются инструкции из скрипта
3) процесс-родитель, из которого была запущена новая копия интерпретатора приостанавливает свою работу
4) по выполнении всех инструкций дочерний процесс интерпретатора завершает свою работу
5) процесс-родитель возобновляет свою работу
Почему это имеет значение? Представьте что у вас есть некоторая иерархическая система скриптов использующих одну переменную, значение которой определяется динамически, на основе нескольких параметров. Почему после запуска скрипта должным образом инициализированная и экспортированная переменная не доступна из консоли, из которой производился запуск и не может быть использована другими скприптами?
У каждого процесса есть своя собственная среда окружения (в это понятие, кроме всего прочего, входят и переменные окружения). Когда мы в контексте дочернего процесса экспортировали переменную, она успешно сохранялась в переменных окружения дочернего процесса и существовала все время пока существовал сам дочерний процесс. По завершению дочернего процесса – когда были выполнены все команды из файла-скрипта, дочерний процесс завершился, вместе с чем его рабочее пространство со всеми экспортируемыми переменными также перестало существовать.
В результате, если у вас есть скрипт test_export.sh следующего содержания
#!/bin/sh
export MYVAR=”some value”;
то результатом следующей последовательности команд:
1) ./test_export.sh
2) echo $MYVAR
будет пустая строка – текущему экземпляру интерпретатора ничего не известно о только что завершившемся процессе интерпретатора, выполнявшего какие-то экспорты в свою среду окружения.
Для того чтобы команды скрипта выполнялись в контексте текущего экземпляра интерпретатора необходимо
использовать команду “source” или его аналог команду “.” – да, команда точка.
1) . ./test_export.sh или source ./test_export.sh
2) echo $MYVAR
Таким образом мы указываем интерпретатору не запускать дополнительный экземпляр для обработки комманд скрипта,а заняться им самому.
А вообще, по-хорошему, переменные окружения должны устанавливаться специальными startup или pre-load-скриптами, выполняющимися при загрузке самой системы, x-window или нового экземпляра консоли – в зависимост от наших конкретных задач. Есть специальные утилиты для управления скриптами, выполняемыми при загрузке системы – update-rc.d, file-rc. Но, при острой необходимости управлять скриптами можно и голыми руками: гуглить “.bashrc”, “.bash_profile”, “.profile”, /etc/rc?.d/rc.N ).
8 comments
Skip to comment form
Спасибо!
Очень помогло.
Спасибо! Очень помогло 🙂 Просто и понятно.
Очень дельная статья!
Небольшое дополнение.
На самом деле для выполнения скрипта something.sh под оператором source bash всё же создаёт копию самого себя с другим PID, как если бы мы запускали его в виде bash something.sh, но после завершения вызова действительно возвращает значения всех созданных/изменённых в нём переменных в родительский bash.
Author
ммм, а это где такое описано?
в сурсах баша форка я в этом случае не нахожу – там все сводится к parse_and_execute в рамках текущего процесса?
А это легко проверяется: создайте скрипт, впишите туда какую-нибудь команду типа sleep и пошлите его в бекграунд с помощью точки. Потом pidof bash или ps-ом увидите, что башей стало на одного больше.
Author
если вы процесс запускаете в бекгранде (не зависимо через сурс или без) – он будет форкнут в отдельном процессе баша.
http://stackoverflow.com/questions/25523059/what-happens-if-i-source-a-script-as-background-process
Да, в самом деле.
Спасибо 🙂
Да и без острой необходимости, bashrc и profile – стандартный способ настроить индивидуальное окружение для аккаунта. Через rc-механизм это не сделать