2

У меня есть следующий скрипт Bash:

#!/bin/bash
echo $MYPROJECT_HOME/bin/myproject_venv/bin/activate
source $MYPROJECT_HOME/bin/myproject_venv/bin/activate
echo $MYPROJECT_HOME/bin/myproject_venv/bin/activate

Разрешения показывают, что файл является исполняемым, и он принадлежит мне. Разрешения:

-rwxr-xr-x

Когда я запускаю скрипт в командной строке, он дважды печатает правильный путь к скрипту activate как я и ожидал. Тем не менее, он неправильно запускает среднюю строку - ту, которая является источником сценария.

Однако если я скопирую эту среднюю строку и запусту ее в командной строке, она будет работать нормально.

Что дает?

2 ответа2

4

Проблема

Он работает отлично (вы можете проверить это, добавив команду echo в исходный файл), проблема в том, что он запускается в другой оболочке. Когда вы запускаете скрипт оболочки (используя bash в качестве примера, но те же идеи применимы и к другим оболочкам), он запускает неинтерактивную, неинтерактивную оболочку для запуска. Это означает, что запускается отдельный мини-экземпляр bash и именно этот bash является источником вашего скрипта. Вот почему переменные, которые вы устанавливаете, отсутствуют в родительской оболочке.

Вы можете проверить это достаточно легко:

$ cat test.sh
#!/bin/bash
export FOO="bar"
echo "FOO in test.sh is : $FOO"

$ export FOO="OOF"
$ echo $FOO
OOF                       ### Here, in the parent shell, $FOO is 'OOF'
$ ./test.sh
FOO in test.sh is : bar   ### In the shell running the script, $FOO is 'bar'
$ echo $FOO
OOF                       ### Back in the parent shell, $FOO is still 'OOF'

Итак, сценарии оболочки запускаются в отдельной, отдельной оболочке и, как указано в help source:

source: source filename [arguments]
    Execute commands from a file in the current shell.

Таким образом, source влияет только на текущую оболочку, которая в случае сценария bash запускается для запуска самого сценария, а не родительской оболочки, в которой вы вводили имя сценария.


Решения

Если вы хотите получить файл, который устанавливает переменные, вы должны сделать это из оболочки, в которой вы работаете, просто запустите команду source напрямую.

В качестве альтернативы, вы можете создать source для всех новых экземпляров оболочки, добавив его в файл запуска bash . Это .profile в OSX и .bashrc в большинстве других случаев. Итак, отредактируйте ваш файл $HOME/.profile и добавьте следующую строку:

source $MYPROJECT_HOME/bin/myproject_venv/bin/activate

Теперь все новые открытые вами терминалы будут иметь файл activate . Или, если вы хотите сделать это по требованию, превратите ваш скрипт в функцию. Добавьте эти строки в ваш .profile:

activate(){
  echo "Sourcing $TEST/activate"
  source $TEST/activate
}

Функции, в отличие от сценариев, не запускают новый экземпляр оболочки и, следовательно, могут изменять оболочку, из которой вы их запускаете. Теперь вы можете запустить activate для получения файла $TEST/activate .

2

Может быть, сценарий activate работает, но работает, устанавливая переменные среды? Если это так, это может вызвать проблемы. В качестве теста я создал два сценария:command и activate . Первый похож на ваш скрипт Bash:

#!/bin/bash
echo $TEST/activate
source $TEST/activate
echo $TEST/activate

и activate это простой однострочник:

export TEST="Hello World!"

Выходные данные показывают, что изменения переменных среды не сохраняются. Вот команды, которые я использовал для запуска, и результаты:

export TEST="/Users/me"
./command

Это, кажется, меняет переменные среды; вот вывод:

/Users/me/activate
Hello World!/activate

Но вернувшись в командную строку, я вижу, что значение $ TEST такое же, как и раньше:

echo $TEST

имеет выход:

/Users/me

Может это твоя проблема?

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .