Вопрос или проблема
Я пытался использовать bash скрипт для добавления или удаления прокси в批量, но скрипт выполняется с запутанными результатами.
Я могу добавлять прокси批量, используя следующий код. Этот код сохранен мной в use_proxy.sh:
#!/bin/bash
PROXY="http://127.0.0.1:10889"
set_proxy() {
export http_proxy="$PROXY"
export https_proxy="$PROXY"
export HTTP_PROXY="$PROXY"
export HTTPS_PROXY="$PROXY"
echo "Прокси установлен на $PROXY"
}
set_proxy
Когда я запускаю этот скрипт (bash use_proxy.sh
) с помощью команды bash, все работает нормально, и выполнение команды env
добавляет адрес прокси
Но я не могу удалить прокси批量, используя следующий код, который сохранен в unset_proxy.sh:
#!/bin/bash
unset_proxy() {
unset http_proxy
unset https_proxy
unset HTTP_PROXY
unset HTTPS_PROXY
echo "Прокси отменен"
}
unset_proxy
Когда я использую этот скрипт (т.е. запускаю bash unset_proxy.sh
), этот скрипт не работает. Когда я выполняю команду env
, я все еще вижу адрес прокси, ранее установленный use_proxy.sh
Почему?
Я обнаружил, что если скрипт запустить с помощью source
(т.е. source unset_proxy.sh
), он выполняется успешно.
Теперь у меня есть новый вопрос: почему bash unset_proxy.sh
не может правильно удалить переменную окружения, в то время как source unset_proxy.sh
успешно удалит переменную окружения?
Когда вы запускаете shell-скрипт, он выполняется в отдельном процессе оболочки. Это означает, что вы не можете запустить скрипт для установки или удаления переменных в текущей оболочке, и экспорт переменной не имеет значения. Возьмем тривиальный пример:
$ cat foo.sh
#!/bin/bash
export foo="bar"
echo "Foo в скрипте '$foo'"
$ $ ./foo.sh
Foo в скрипте 'bar'
$ echo "Foo вне скрипта: '$foo'"
Foo вне скрипта: ''
Как видите, выполнение скрипта не установило переменную. Однако подключение скрипта с помощью .
(или, если ваша оболочка bash
, используя source
, что одно и то же), который выполнит команды в текущей оболочке, позволяет вам устанавливать и удалять переменные:
$ . ./foo.sh
Foo в скрипте 'bar'
$ echo "Foo вне скрипта: '$foo'"
Foo вне скрипта: 'bar'
Таким образом, использование .
вместо запуска скриптов, вероятно, будет тем, что вам нужно. Еще проще, добавьте две функции в ваш ~/.bashrc
, и затем вы сможете просто запускать их в любой оболочке и они будут работать “из коробки”. Нет необходимости в отдельных скриптах, просто скопируйте и вставьте код прямо в ваш ~/.bashrc
.
Смотрите В чем разница между подключением (‘.’ или ‘source’) и выполнением файла в bash?
Ответ или решение
Для решения вашей проблемы с удалением переменных окружения в скрипте Bash важно понять различие между выполнением скрипта и его «соседним» запуском, что происходит при использовании команды source
или .
.
Проблема
Когда вы запускаете скрипт в терминале с помощью команды, например, bash unset_proxy.sh
, этот скрипт выполняется в новом дочернем процессе. Все изменения, внесенные в переменные окружения в этом дочернем процессе, не отражаются в родительском процессе (вашем текущем терминале). Это будет очевидно, поскольку после завершения скрипта переменные остаются в исходном состоянии.
Решение
Чтобы удалить переменные окружения так, как вы и намеревались, необходимо использовать команду source
(или сокращенно .
) вместо обычного запуска скрипта. Например:
source unset_proxy.sh
Или:
. unset_proxy.sh
Таким образом, команды внутри unset_proxy.sh
будут выполняться в вашем текущем контексте оболочки, и переменные окружения будут действительно удалены.
Примеры
-
Создание и выполнение скрипта (дочерний процесс):
# foo.sh #!/bin/bash export foo="bar" echo "Foo в скрипте: '$foo'"
Выполнение:
bash foo.sh echo "Foo вне скрипта: '$foo'" # Вывод: Foo вне скрипта: ''
-
Использование
source
(текущий процесс):# foo.sh #!/bin/bash export foo="bar" echo "Foo в скрипте: '$foo'"
Выполнение:
source foo.sh echo "Foo вне скрипта: '$foo'" # Вывод: Foo вне скрипта: 'bar'
Рекомендации
Если вы часто работаете со скриптами для установки и удаления переменных окружения, вы можете рассмотреть возможность добавления этих функций прямо в ваш ~/.bashrc
файл. Это упростит настройку среды в вашем терминале для любой сессии. Например:
# Добавьте в ~/.bashrc
set_proxy() {
export http_proxy="http://127.0.0.1:10889"
export https_proxy="http://127.0.0.1:10889"
}
unset_proxy() {
unset http_proxy
unset https_proxy
}
После этого вы можете выполнять set_proxy
и unset_proxy
напрямую в вашем терминале, не создавая отдельные скрипты.
Заключение
Использование source
или .
для запуска вашего скрипта — это лучший метод изменения переменных окружения в текущей сессии. Убедитесь, что вы понимаете отличие между выполнением в дочернем процессе и выполнением в текущем процессе, чтобы избежать подобных недоразумений в будущем.