Команда source – как выполнить bash-скрипт не запуская второй процесс bash

В линукс-системах, в консоли, каждый скрипт запускается следующим образом:

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

    • om on September 9, 2015 at 7:02 pm
    • Reply

    Спасибо!
    Очень помогло.

  1. Спасибо! Очень помогло 🙂 Просто и понятно.

  2. Очень дельная статья!
    Небольшое дополнение.
    На самом деле для выполнения скрипта something.sh под оператором source bash всё же создаёт копию самого себя с другим PID, как если бы мы запускали его в виде bash something.sh, но после завершения вызова действительно возвращает значения всех созданных/изменённых в нём переменных в родительский bash.

    1. ммм, а это где такое описано?
      в сурсах баша форка я в этом случае не нахожу – там все сводится к parse_and_execute в рамках текущего процесса?

      1. А это легко проверяется: создайте скрипт, впишите туда какую-нибудь команду типа sleep и пошлите его в бекграунд с помощью точки. Потом pidof bash или ps-ом увидите, что башей стало на одного больше.

        1. если вы процесс запускаете в бекгранде (не зависимо через сурс или без) – он будет форкнут в отдельном процессе баша.

          http://stackoverflow.com/questions/25523059/what-happens-if-i-source-a-script-as-background-process

          1. Да, в самом деле.
            Спасибо 🙂

  3. Да и без острой необходимости, bashrc и profile – стандартный способ настроить индивидуальное окружение для аккаунта. Через rc-механизм это не сделать

Leave a Reply

Your email address will not be published.