На этот вопрос уже есть ответ:
Я пытаюсь написать сценарий оболочки, который при запуске устанавливает некоторые переменные окружения, которые останутся установленными в оболочке вызывающего.
setenv FOO foo
в csh / tcsh или
export FOO=foo
в sh / bash устанавливают его только во время выполнения скрипта.
Я уже знаю, что
source myscript
будут запускать команды сценария, а не запускать новую оболочку, и это может привести к настройке среды «вызывающего».
Но вот в чем проблема:
Я хочу, чтобы этот скрипт вызывался из bash или csh. Другими словами, я хочу, чтобы пользователи любой оболочки могли запускать мой сценарий и изменять среду своей оболочки. Поэтому «источник» не будет работать для меня, так как пользователь, запускающий csh, не может создать сценарий bash, а пользователь, запускающий bash, не может создать сценарий csh.
Есть ли какое-то разумное решение, которое не предполагает написания и поддержки ДВУХ версий сценария?
Ваш процесс оболочки имеет копию среды родительского процесса и вообще не имеет доступа к среде родительского процесса. Когда процесс оболочки завершает работу, любые изменения, внесенные в его среду, теряются. Выбор файла сценария является наиболее часто используемым методом настройки среды оболочки. Вы можете просто захотеть откусить пулю и сохранить один для каждого из двух вариантов оболочки.
Кроме записи условных выражений, в зависимости от того, что установлено в $ SHELL / $ TERM, нет. Что не так с использованием Perl? Это довольно вездесущий (я не могу думать об одном варианте UNIX, у которого его нет), и он избавит вас от хлопот.
Это не то, что я бы назвал выдающимся, но это также работает, если вам все равно нужно вызвать скрипт из оболочки. Это не очень хорошее решение, но для одной статической переменной среды оно работает достаточно хорошо.
1.) Создайте сценарий с условием, которое выходит из 0 (успешно) или 1 (не успешно)
if [[ $foo == "True" ]]; then
exit 0
else
exit 1
2.) Создайте псевдоним, который зависит от кода выхода .
alias='myscript.sh && export MyVariable'
Вы вызываете псевдоним, который вызывает скрипт, который оценивает условие, которое требуется для выхода из нуля через '& amp;' для того, чтобы установить переменную среды в родительской оболочке.
Это flotsam, но это может быть полезно в крайнем случае.
Я не вижу никакого ответа, документирующего, как обойти эту проблему с взаимодействующими процессами. Распространенный шаблон с такими вещами, как ssh-agent
, заключается в том, чтобы дочерний процесс печатал выражение, которое родительский процесс может eval
.
bash$ eval $(shh-agent)
Например, ssh-agent
имеет опции для выбора Csh или Bourne-совместимого выходного синтаксиса.
bash$ ssh-agent
SSH2_AUTH_SOCK=/tmp/ssh-era/ssh2-10690-agent; export SSH2_AUTH_SOCK;
SSH2_AGENT_PID=10691; export SSH2_AGENT_PID;
echo Agent pid 10691;
(Это приводит к тому, что агент запускается, но не позволяет вам фактически использовать его, если только вы сейчас не скопировали и не вставили этот вывод в приглашение оболочки.) Сравнить:
bash$ ssh-agent -c
setenv SSH2_AUTH_SOCK /tmp/ssh-era/ssh2-10751-agent;
setenv SSH2_AGENT_PID 10752;
echo Agent pid 10752;
(Как видите, csh
и tcsh
используют setenv
для установки переменных.)
Ваша собственная программа может сделать это тоже.
bash$ foo=$(makefoo)
Ваш скрипт makefoo
просто вычислит и напечатает значение и позволит вызывающей стороне делать с ним все, что он хочет - назначение его переменной является распространенным случаем, но, вероятно, это не то, что вы хочу жестко закодировать в инструмент, который производит значение.
В OS X bash вы можете сделать следующее:
Создать файл сценария bash для сброса переменной
#!/bin/bash
unset http_proxy
Сделать файл исполняемым
sudo chmod 744 unsetvar
Создайте псевдоним
alias unsetvar='source /your/path/to/the/script/unsetvar'
. Он должен быть готов к использованию, если к пути добавлена папка с файлом сценария.
#000000
и т.п..
– Sacha Epskamp
11.02.2020, 08:29
Я создал решение, используя трубы, eval и сигнал.
parent() {
if [ -z "$G_EVAL_FD" ]; then
die 1 "Rode primeiro parent_setup no processo pai"
fi
if [ $(ppid) = "$" ]; then
"$@"
else
kill -SIGUSR1 $
echo "$@">&$G_EVAL_FD
fi
}
parent_setup() {
G_EVAL_FD=99
tempfile=$(mktemp -u)
mkfifo "$tempfile"
eval "exec $G_EVAL_FD<>'$tempfile'"
rm -f "$tempfile"
trap "read CMD <&$G_EVAL_FD; eval \"\$CMD\"" USR1
}
parent_setup #on parent shell context
( A=1 ); echo $A # prints nothing
( parent A=1 ); echo $A # prints 1
Может работать с любой командой.
Я сделал это много лет назад. Если я правильно помню, я включил псевдоним в каждый из .bashrc и .cshrc с параметрами, совмещающими соответствующие формы установки среды в общую форму.
Тогда скрипт, который вы будете использовать в любой из двух оболочек, имеет команду с этой последней формой, подходящей для каждого псевдонима.
Если я найду конкретные псевдонимы, я опубликую их.
col2rgb
и проверить на ошибку. Это сказало исходный код C для col2rgb
isn' t слишком ужасный, и показывает другой случай: col2rgb(0)
дает Вам цвет фона графика.
– hadley
11.02.2020, 08:29
Другой вариант - использовать «Модули среды» ( http://modules.sourceforge.net/ ). Это, к сожалению, вводит третий язык в смесь. Вы определяете среду с помощью языка Tcl, но есть несколько удобных команд для типичных модификаций (prepend vs. append vs set). Вам также необходимо установить модули среды. Затем вы можете использовать module load *XXX*
, чтобы назвать желаемую среду. Команда модуля - это в основном причудливый псевдоним для механизма eval
, описанного выше Томасом Каммейером. Основным преимуществом здесь является то, что вы можете поддерживать среду на одном языке и полагаться на «Модули среды», чтобы преобразовать ее в sh, ksh, bash, csh, tcsh, zsh, python (?!? !!) и т. Д.
Вы всегда можете использовать псевдонимы
alias your_env='source ~/scripts/your_env.sh'
. Технически, это правильно - только 'eval' не разветвляется на другую оболочку. Однако с точки зрения приложения, которое вы пытаетесь запустить в измененной среде, разница равна нулю: дочерний объект наследует среду своего родителя, поэтому (измененная) среда передается всем нисходящим процессам.
Ipso facto, измененная переменная окружения «прилипает» - до тех пор, пока вы работаете под родительской программой / оболочкой.
Если абсолютно необходимо, чтобы переменная окружения оставалась после выхода из родительского объекта (Perl или shell), необходимо, чтобы родительская оболочка выполнила тяжелую работу. Один из методов, которые я видел в документации, заключается в том, что текущий скрипт порождает исполняемый файл с необходимым языком «экспорта», а затем обманывает родительскую оболочку при его выполнении - всегда осознавая тот факт, что вам нужно предисловие введите команду 'source', если вы пытаетесь оставить энергонезависимую версию модифицированной среды. Клюге в лучшем случае.
Второй метод заключается в изменении сценария, который запускает среду оболочки (.bashrc или что-либо еще), чтобы он содержал измененный параметр. Это может быть опасно - если вы запустите скрипт инициализации, это может сделать вашу оболочку недоступной при следующем запуске. Существует множество инструментов для изменения текущей оболочки; добавив необходимые настройки в «панель запуска», вы также эффективно продвигаете эти изменения. Вообще не очень хорошая идея; если вам нужны только изменения среды для определенного набора приложений, вам придется вернуться и вернуть скрипт запуска оболочки в его первоначальное состояние (с использованием vi или чего-либо другого) впоследствии.
Короче говоря, нет хороших (и простых) методов. Предположительно, это было затруднено, чтобы гарантировать, что безопасность системы не была безвозвратно скомпрометирована.
Вы можете указать дочернему процессу печатать его переменные окружения (вызывая «env»), затем перебирать напечатанные переменные окружения в родительском процессе и вызывать «export» для этих переменных.
Следующий код основан на Захват вывода find. -print0 в массив bash
Если родительской оболочкой является bash, вы можете использовать
while IFS= read -r -d Если родительской оболочкой является дефис, то read
не обеспечивает флаг -d и код усложняются
TMPDIR=$(mktemp -d)
mkfifo $TMPDIR/fifo
(bash -s << "EOF"
export VARNAME=something
while IFS= read -r -d \0' line; do
echo $(printf '%q' "$line")
done < <(env -0)
EOF
) > $TMPDIR/fifo &
while read -r line; do export "$(eval echo $line)"; done < $TMPDIR/fifo
rm -r $TMPDIR
echo $VARNAME
\0' line; do
export "$line"
done < <(bash -s <<< 'export VARNAME=something; env -0')
echo $VARNAME
Если родительской оболочкой является дефис, то read
не обеспечивает флаг -d и код усложняются
TMPDIR=$(mktemp -d)
mkfifo $TMPDIR/fifo
(bash -s << "EOF"
export VARNAME=something
while IFS= read -r -d \0' line; do
echo $(printf '%q' "$line")
done < <(env -0)
EOF
) > $TMPDIR/fifo &
while read -r line; do export "$(eval echo $line)"; done < $TMPDIR/fifo
rm -r $TMPDIR
echo $VARNAME
Другой обходной путь, о котором я не упомянул, - это запись значения переменной в файл.
Я столкнулся с очень похожей проблемой, в которой я хотел иметь возможность выполнить последний набор тестов (вместо всех моих тестов). Мой первый план состоял в том, чтобы написать одну команду для установки переменной env TESTCASE, а затем создать другую команду, которая использовала бы ее для запуска теста. Излишне говорить, что у меня была та же самая проблема, что и у вас.
Но потом я придумал этот простой взлом:
Первая команда (testset
):
#!/bin/bash
if [ $# -eq 1 ]
then
echo $1 > ~/.TESTCASE
echo "TESTCASE has been set to: $1"
else
echo "Come again?"
fi
Вторая команда (testrun
):
#!/bin/bash
TESTCASE=$(cat ~/.TESTCASE)
drush test-run $TESTCASE
Краткий ответ - нет, вы не можете изменить среду родительского процесса, но похоже, что вам нужна среда с пользовательскими переменными среды и оболочкой, которую выбрал пользователь.
Так почему бы не просто что-то вроде
#!/usr/bin/env bash
FOO=foo $SHELL
Тогда, когда вы закончите с окружающей средой, просто exit
.
Добавьте флаг -l вверху вашего bash-скрипта, т.е.
#!/usr/bin/env bash -l
...
export NAME1="VALUE1"
export NAME2="VALUE2"
Значения с NAME1
и NAME2
теперь будут экспортированы в текущую среду, однако эти изменения не являются постоянными. Если вы хотите, чтобы они были постоянными, вам нужно добавить их в ваш файл .bashrc
или другой файл инициализации.
Из справочных страниц:
-l Make bash act as if it had been invoked as a login shell (see INVOCATION below).
Это работает & mdash; это не то, что я бы использовал, но это «работает». Давайте создадим скрипт teredo
для установки переменной среды TEREDO_WORMS
:
#!/bin/ksh
export TEREDO_WORMS=ukelele
exec $SHELL -i
Он будет интерпретироваться оболочкой Korn, экспортирует переменную среды, а затем заменит себя новой интерактивной оболочкой.
Перед запуском этого скрипта мы установили SHELL
в среде для оболочки C, а переменная среды TEREDO_WORMS
не установлена:
% env | grep SHELL
SHELL=/bin/csh
% env | grep TEREDO
%
Когда скрипт запущен, вы в новой оболочке - другая интерактивная оболочка C, но установлена переменная окружения:
% teredo
% env | grep TEREDO
TEREDO_WORMS=ukelele
%
При выходе из этой оболочки исходная оболочка вступает во владение:
% exit
% env | grep TEREDO
%
Среда переменная не установлена в среде исходной оболочки. Если вы используете exec teredo
для запуска команды, то исходная интерактивная оболочка заменяется оболочкой Korn, которая задает среду, а затем, в свою очередь, заменяется новой интерактивной оболочкой C:
% exec teredo
% env | grep TEREDO
TEREDO_WORMS=ukelele
%
Если вы наберете exit
(или Control-D kbd>), то ваша оболочка закроется, возможно, выйдет из этого окна или вернет вас на предыдущий уровень оболочки, с которого начались эксперименты.
Тот же механизм работает для оболочки Bash или Korn. Вы можете обнаружить, что подсказка после команд выхода появляется в забавных местах.
Обратите внимание на обсуждение в комментариях. Это не решение, которое я бы рекомендовал, но оно достигает заявленной цели единого сценария, чтобы установить среду, которая работает со всеми оболочками (которые принимают опцию -i
для создания интерактивной оболочки). Вы также можете добавить "$@"
после опции для передачи любых других аргументов, что может сделать оболочку пригодной для использования в качестве общего инструмента 'set environment and execute command'. Возможно, вы захотите опустить -i
, если есть другие аргументы, приводящие к:
#!/bin/ksh
export TEREDO_WORMS=ukelele
exec $SHELL "${@-'-i'}"
Бит "${@-'-i'}"
означает «если список аргументов содержит хотя бы один аргумент, используйте исходный список аргументов; в противном случае замените -i
несуществующими аргументами ».
exec
). Главная причина не сделать так состоит в том, что у Вас есть случайный уровень оболочки, таким образом, you' d должны сделать дополнительное управление-D, чтобы выйти из системы в том окне.
– Jonathan Leffler
09.04.2013, 04:53
Это «своего рода» возможно благодаря использованию gdb и setenv (3) , хотя мне трудно рекомендовать это делать. (Кроме того, то есть самая последняя версия Ubuntu на самом деле не позволит вам сделать это, не сказав ядру, чтобы он был более разборчив в отношении ptrace, и то же самое может пойти и на другие дистрибутивы).
$ cat setfoo
#! /bin/bash
gdb /proc/${PPID}/exe ${PPID} <<END >/dev/null
call setenv("foo", "bar", 0)
END
$ echo $foo
$ ./setfoo
$ echo $foo
bar
Вы должны использовать модули, см. http://modules.sourceforge.net/
РЕДАКТИРОВАТЬ: пакет модулей не обновлялся с 2012 года, но все еще работает хорошо для основ. Все новые функции, звонки и свистки происходят в lmod в этот день (что мне нравится больше): https://www.tacc.utexas.edu/research-development/tacc-projects/lmod
В моем .bash_profile у меня есть:
# No Proxy
function noproxy
{
/usr/local/sbin/noproxy #turn off proxy server
unset http_proxy HTTP_PROXY https_proxy HTTPs_PROXY
}
# Proxy
function setproxy
{
sh /usr/local/sbin/proxyon #turn on proxy server
http_proxy=http://127.0.0.1:8118/
HTTP_PROXY=$http_proxy
https_proxy=$http_proxy
HTTPS_PROXY=$https_proxy
export http_proxy https_proxy HTTP_PROXY HTTPS_PROXY
}
Поэтому, когда я хочу отключить прокси-сервер, функции запускаются в оболочке входа в систему и устанавливают переменные в соответствии с ожиданиями и желаниями.
Используйте синтаксис вызова «сценарий точечного пространства». Например, вот как это сделать, используя полный путь к скрипту:
. /path/to/set_env_vars.sh
А вот как это сделать, если вы находитесь в том же каталоге, что и скрипт:
. set_env_vars.sh
Они выполняют скрипт под текущей оболочкой вместо загрузки другой (что произойдет, если вы это сделаете ./set_env_vars.sh
). Поскольку он работает в той же оболочке, заданные переменные среды будут доступны после его выхода.
Это то же самое, что и вызов source set_env_vars.sh
, но он короче набирает текст и может работать в некоторых местах, где source
нет.
Вы не сможете изменить оболочку вызывающей стороны, потому что она находится в другом контексте процесса. Когда дочерние процессы наследуют переменные вашей оболочки, они сами наследуют копии.
Одна вещь, которую вы можете сделать, это написать скрипт, который будет генерировать правильные команды для tcsh или sh, основываясь на том, как он вызывается. Если ваш скрипт "setit", то выполните:
ln -s setit setit-sh
и
ln -s setit setit-csh
Теперь либо напрямую, либо по псевдониму, вы делаете это из sh
eval `setit-sh`
или это из csh
eval `setit-csh`
setit использует $ 0 для определения стиля вывода.
Это напоминает то, как люди используют для установки переменной окружения TERM.
Преимущество здесь в том, что setit просто написан в любой оболочке, которая вам нравится, например:
#!/bin/bash
arg0=[114]
arg0=${arg0##*/}
for nv in \
NAME1=VALUE1 \
NAME2=VALUE2
do
if [ x$arg0 = xsetit-sh ]; then
echo 'export '$nv' ;'
elif [ x$arg0 = xsetit-csh ]; then
echo 'setenv '${nv%%=*}' '${nv##*=}' ;'
fi
done
с символическими ссылками, указанными выше, и eval из выражения в кавычках, это имеет желаемый результат.
Чтобы упростить вызов для csh, tcsh или аналогичных оболочек:
alias dosetit 'eval `setit-csh`'
или для sh, bash и т. П .:
alias dosetit='eval `setit-sh`'
Одна приятная вещь в этом заключается в том, что вам нужно только вести список в одном месте. Теоретически вы можете даже вставить список в файл и поставить cat nvpairfilename
между «in» и «do».
Это почти то же самое, что и настройки терминала оболочки входа в систему: сценарий должен выводить статистику для выполнения в оболочке входа. Псевдоним обычно используется для упрощения вызова, как в «tset vt100». Как уже упоминалось в другом ответе, на сервере новостей INN UseNet есть аналогичные функции.
Вы можете вызвать еще один Bash с другим bash_profile. Также вы можете создать специальный bash_profile для использования в среде multi-bashprofile.
Помните, что вы можете использовать функции внутри bashprofile, и эти функции будут доступны во всем мире. например, «функция user {export USER_NAME $ 1}» может устанавливать переменную во время выполнения, например: user olegchir & amp; & amp; env | грег олегчир