shell脚本可以设置调用shell的环境变量吗?

发布于 2024-07-13 03:55:38 字数 516 浏览 12 评论 0原文

我正在尝试编写一个 shell 脚本,该脚本在运行时将设置一些环境变量,这些变量将在调用者的 shell 中保持设置状态。

setenv FOO foo

在 csh/tcsh 或

export FOO=foo

sh/bash 中仅在脚本执行期间设置它。

我已经知道它将

source myscript

运行脚本的命令而不是启动新的 shell,这可能会导致设置“调用者”环境。

但问题是:

我希望这个脚本可以从 bash 或 csh 调用。 换句话说,我希望任一 shell 的用户都能够运行我的脚本并更改其 shell 环境。 所以“source”对我不起作用,因为运行 csh 的用户无法获取 bash 脚本,而运行 bash 的用户也无法获取 csh 脚本。

是否有任何合理的解决方案,不需要在脚本上编写和维护两个版本?

I'm trying to write a shell script that, when run, will set some environment variables that will stay set in the caller's shell.

setenv FOO foo

in csh/tcsh, or

export FOO=foo

in sh/bash only set it during the script's execution.

I already know that

source myscript

will run the commands of the script rather than launching a new shell, and that can result in setting the "caller's" environment.

But here's the rub:

I want this script to be callable from either bash or csh. In other words, I want users of either shell to be able to run my script and have their shell's environment changed. So 'source' won't work for me, since a user running csh can't source a bash script, and a user running bash can't source a csh script.

Is there any reasonable solution that doesn't involve having to write and maintain TWO versions on the script?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(20

古镇旧梦 2024-07-20 03:55:39

使用“点空间脚本”调用语法。 例如,以下是如何使用脚本的完整路径执行此操作:

. /path/to/set_env_vars.sh

如果您与脚本位于同一目录中,则以下是如何执行此操作:

. set_env_vars.sh

这些在当前 shell 下执行脚本,而不是加载另一个脚本(即如果你这样做./set_env_vars.sh会发生什么)。 因为它运行在同一个shell中,所以你设置的环境变量在它退出时将可用。

这与调用 source set_env_vars.sh 是一样的,但它的输入时间更短,并且可能在某些 source 不起作用的地方起作用。

Use the "dot space script" calling syntax. For example, here's how to do it using the full path to a script:

. /path/to/set_env_vars.sh

And here's how to do it if you're in the same directory as the script:

. set_env_vars.sh

These execute the script under the current shell instead of loading another one (which is what would happen if you did ./set_env_vars.sh). Because it runs in the same shell, the environmental variables you set will be available when it exits.

This is the same thing as calling source set_env_vars.sh, but it's shorter to type and might work in some places where source doesn't.

氛圍 2024-07-20 03:55:39

您的 shell 进程拥有父进程环境的副本,并且无法访问父进程的环境。 当 shell 进程终止时,您对其环境所做的任何更改都会丢失。 获取脚本文件是配置 shell 环境最常用的方法,您可能只是想硬着头皮为两种 shell 风格中的每一种维护一个脚本文件。

Your shell process has a copy of the parent's environment and no access to the parent process's environment whatsoever. When your shell process terminates any changes you've made to its environment are lost. Sourcing a script file is the most commonly used method for configuring a shell environment, you may just want to bite the bullet and maintain one for each of the two flavors of shell.

乜一 2024-07-20 03:55:39

您将无法修改调用者的 shell,因为它位于不同的进程上下文中。 当子进程继承 shell 的变量时,它们是
继承副本本身。

您可以做的一件事是编写一个为 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 可以用您喜欢的任何 shell 编写,如下所示:

#!/bin/bash
arg0=$0
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 或类似 shell 的调用:

alias dosetit 'eval `setit-csh`'

或对 sh、bash 等的调用:

alias dosetit='eval `setit-sh`'

这样做的一个好处是您只需在一处维护该列表。
理论上,您甚至可以将列表粘贴到文件中,并将 cat nvpairfilename 放在“in”和“do”之间。

这几乎就是登录 shell 终端设置的过去方式:脚本将输出要在登录 shell 中执行的语句。 别名通常用于使调用变得简单,如“tset vt100”。 正如另一个答案中提到的,INN UseNet 新闻服务器中也有类似的功能。

You're not going to be able to modify the caller's shell because it's in a different process context. When child processes inherit your shell's variables, they're
inheriting copies themselves.

One thing you can do is to write a script that emits the correct commands for tcsh
or sh based how it's invoked. If you're script is "setit" then do:

ln -s setit setit-sh

and

ln -s setit setit-csh

Now either directly or in an alias, you do this from sh

eval `setit-sh`

or this from csh

eval `setit-csh`

setit uses $0 to determine its output style.

This is reminescent of how people use to get the TERM environment variable set.

The advantage here is that setit is just written in whichever shell you like as in:

#!/bin/bash
arg0=$0
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

with the symbolic links given above, and the eval of the backquoted expression, this has the desired result.

To simplify invocation for csh, tcsh, or similar shells:

alias dosetit 'eval `setit-csh`'

or for sh, bash, and the like:

alias dosetit='eval `setit-sh`'

One nice thing about this is that you only have to maintain the list in one place.
In theory you could even stick the list in a file and put cat nvpairfilename between "in" and "do".

This is pretty much how login shell terminal settings used to be done: a script would output statments to be executed in the login shell. An alias would generally be used to make invocation simple, as in "tset vt100". As mentioned in another answer, there is also similar functionality in the INN UseNet news server.

一抹苦笑 2024-07-20 03:55:39

在我的 .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
}

所以当我想禁用代理时,
函数在登录 shell 中运行并设置变量
正如预期和想要的那样。

In my .bash_profile I have :

# 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
}

So when I want to disable the proxy,
the function(s) run in the login shell and sets the variables
as expected and wanted.

向日葵 2024-07-20 03:55:39

通过使用 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

It's "kind of" possible through using gdb and setenv(3), although I have a hard time recommending actually doing this. (Additionally, i.e. the most recent ubuntu won't actually let you do this without telling the kernel to be more permissive about ptrace, and the same may go for other distros as well).

$ cat setfoo
#! /bin/bash

gdb /proc/${PPID}/exe ${PPID} <<END >/dev/null
call setenv("foo", "bar", 0)
END
$ echo $foo

$ ./setfoo
$ echo $foo
bar
木格 2024-07-20 03:55:39

这有效——这不是我会用的,但它“有效”。 让我们创建一个脚本 teredo 来设置环境变量 TEREDO_WORMS

#!/bin/ksh
export TEREDO_WORMS=ukelele
exec $SHELL -i

它将由 Korn shell 解释,导出环境变量,然后用新的交互式 shell 替换自身。

在运行此脚本之前,我们已将环境中的 SHELL 设置为 C shell,并且未设置环境变量 TEREDO_WORMS

% env | grep SHELL
SHELL=/bin/csh
% env | grep TEREDO
%

当脚本运行时,您处于新 shell,另一个交互式 C shell,但设置了环境变量:

% teredo
% env | grep TEREDO
TEREDO_WORMS=ukelele
%

当您退出此 shell 时,原始 shell 接管:

% exit
% env | grep TEREDO
%

原始 shell 的环境中未设置环境变量。 如果您使用 exec teredo 运行该命令,则原始交互式 shell 会被设置环境的 Korn shell 替换,然后又会被新的交互式 C shell 替换:

% exec teredo
% env | grep TEREDO
TEREDO_WORMS=ukelele
%

如果您键入exit(或 Control-D),然后您的 shell 退出,可能会将您从该窗口注销,或者带您返回到实验开始处的上一个 shell 级别。

相同的机制适用于 Bash 或 Korn shell。 您可能会发现退出命令后的提示出现在有趣的地方。


请注意评论中的讨论。 这不是我推荐的解决方案,但它确实实现了单个脚本的既定目的,以设置适用于所有 shell 的环境(接受 -i 选项来创建交互式 shell)。 您还可以在选项后添加 "$@" 来转发任何其他参数,这可能会使 shell 用作通用的“设置环境和执行命令”工具。 如果还有其他参数,您可能需要省略 -i,从而导致:

#!/bin/ksh
export TEREDO_WORMS=ukelele
exec $SHELL "${@-'-i'}"

"${@-'-i'}" 位表示“如果参数列表”包含至少一个参数,使用原始参数列表; 否则,用 -i 替换不存在的参数'。

This works — it isn't what I'd use, but it 'works'. Let's create a script teredo to set the environment variable TEREDO_WORMS:

#!/bin/ksh
export TEREDO_WORMS=ukelele
exec $SHELL -i

It will be interpreted by the Korn shell, exports the environment variable, and then replaces itself with a new interactive shell.

Before running this script, we have SHELL set in the environment to the C shell, and the environment variable TEREDO_WORMS is not set:

% env | grep SHELL
SHELL=/bin/csh
% env | grep TEREDO
%

When the script is run, you are in a new shell, another interactive C shell, but the environment variable is set:

% teredo
% env | grep TEREDO
TEREDO_WORMS=ukelele
%

When you exit from this shell, the original shell takes over:

% exit
% env | grep TEREDO
%

The environment variable is not set in the original shell's environment. If you use exec teredo to run the command, then the original interactive shell is replaced by the Korn shell that sets the environment, and then that in turn is replaced by a new interactive C shell:

% exec teredo
% env | grep TEREDO
TEREDO_WORMS=ukelele
%

If you type exit (or Control-D), then your shell exits, probably logging you out of that window, or taking you back to the previous level of shell from where the experiments started.

The same mechanism works for Bash or Korn shell. You may find that the prompt after the exit commands appears in funny places.


Note the discussion in the comments. This is not a solution I would recommend, but it does achieve the stated purpose of a single script to set the environment that works with all shells (that accept the -i option to make an interactive shell). You could also add "$@" after the option to relay any other arguments, which might then make the shell usable as a general 'set environment and execute command' tool. You might want to omit the -i if there are other arguments, leading to:

#!/bin/ksh
export TEREDO_WORMS=ukelele
exec $SHELL "${@-'-i'}"

The "${@-'-i'}" bit means 'if the argument list contains at least one argument, use the original argument list; otherwise, substitute -i for the non-existent arguments'.

原来分手还会想你 2024-07-20 03:55:39

您应该使用模块,请参阅 http://modules.sourceforge.net/

编辑:模块包尚未自 2012 年以来更新,但基本功能仍然可以正常工作。 所有的新功能、花哨的功能都发生在 lmod 今天(我更喜欢它): https://www.tacc.utexas.edu/research-development/tacc-projects/lmod

You should use modules, see http://modules.sourceforge.net/

EDIT: The modules package has not been updated since 2012 but still works ok for the basics. All the new features, bells and whistles happen in lmod this day (which I like it more): https://www.tacc.utexas.edu/research-development/tacc-projects/lmod

厌倦 2024-07-20 03:55:39

我没有看到提到的另一个解决方法是将变量值写入文件。

我遇到了一个非常类似的问题,我希望能够运行最后一组测试(而不是所有测试)。 我的第一个计划是编写一个命令来设置环境变量 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

Another workaround that I don't see mentioned is to write the variable value to a file.

I ran into a very similar issue where I wanted to be able to run the last set test (instead of all my tests). My first plan was to write one command for setting the env variable TESTCASE, and then have another command that would use this to run the test. Needless to say that I had the same exact issue as you did.

But then I came up with this simple hack:

First command ( testset ):

#!/bin/bash

if [ $# -eq 1 ]
then
  echo $1 > ~/.TESTCASE
  echo "TESTCASE has been set to: $1"
else
  echo "Come again?"
fi

Second command (testrun ):

#!/bin/bash

TESTCASE=$(cat ~/.TESTCASE)
drush test-run $TESTCASE
身边 2024-07-20 03:55:39

您可以指示子进程打印其环境变量(通过调用“env”),然后循环父进程中打印的环境变量并对这些变量调用“export”。

以下代码基于 捕获 find 的输出。 -print0 到 bash 数组

如果父 shell 是 bash,则可以使用

while IFS= read -r -d 

如果父 shell 是破折号,则 read 不提供 -d 标志,代码会变得更多复杂的

TMPDIR=$(mktemp -d)
mkfifo $TMPDIR/fifo
(bash -s << "EOF"
    export VARNAME=something
    while IFS= read -r -d 
\0' line; do
    export "$line"
done < <(bash -s <<< 'export VARNAME=something; env -0')
echo $VARNAME

如果父 shell 是破折号,则 read 不提供 -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

如果父 shell 是破折号,则 read 不提供 -d 标志,代码会变得更多复杂的

You can instruct the child process to print its environment variables (by calling "env"), then loop over the printed environment variables in the parent process and call "export" on those variables.

The following code is based on Capturing output of find . -print0 into a bash array

If the parent shell is the bash, you can use

while IFS= read -r -d 

If the parent shell is the dash, then read does not provide the -d flag and the code gets more complicated

TMPDIR=$(mktemp -d)
mkfifo $TMPDIR/fifo
(bash -s << "EOF"
    export VARNAME=something
    while IFS= read -r -d 
\0' line; do
    export "$line"
done < <(bash -s <<< 'export VARNAME=something; env -0')
echo $VARNAME

If the parent shell is the dash, then read does not provide the -d flag and the code gets more complicated


\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

If the parent shell is the dash, then read does not provide the -d flag and the code gets more complicated

还如梦归 2024-07-20 03:55:39

在 OS X bash 下,您可以执行以下操作:

创建 bash 脚本文件以取消设置变量

#!/bin/bash
unset http_proxy

使文件可执行

sudo chmod 744 unsetvar

创建别名

alias unsetvar='source /your/path/to/the/script/unsetvar'

只要您将包含脚本文件的文件夹附加到路径中,它就应该可以使用了。

Under OS X bash you can do the following:

Create the bash script file to unset the variable

#!/bin/bash
unset http_proxy

Make the file executable

sudo chmod 744 unsetvar

Create alias

alias unsetvar='source /your/path/to/the/script/unsetvar'

It should be ready to use so long you have the folder containing your script file appended to the path.

毁梦 2024-07-20 03:55:39

您可以使用不同的 bash_profile 调用另一个 Bash。
此外,您可以创建特殊的 bash_profile 以在多 bashprofile 环境中使用。

请记住,您可以在 bashprofile 中使用函数,并且该函数将在全局范围内可用。
例如,“function user {export USER_NAME $1 }”可以在运行时设置变量,例如:user olegchir && 环境| 格列普·奥莱格希尔

You can invoke another one Bash with the different bash_profile.
Also, you can create special bash_profile for using in multi-bashprofile environment.

Remember that you can use functions inside of bashprofile, and that functions will be avialable globally.
for example, "function user { export USER_NAME $1 }" can set variable in runtime, for example: user olegchir && env | grep olegchir

小ぇ时光︴ 2024-07-20 03:55:39

另一种选择是使用“环境模块”(http://modules.sourceforge.net/)。 不幸的是,这引入了第三种语言。 您可以使用 Tcl 语言定义环境,但有一些方便的命令可用于典型修改(前置、附加、设置)。 您还需要安装环境模块。 然后,您可以使用 module load *XXX* 来命名您想要的环境。 module 命令基本上是 Thomas Kammeyer 上面描述的 eval 机制的一个奇特别名。 这里的主要优点是你可以用一种语言维护环境,并依靠“环境模块”将其翻译为 sh、ksh、bash、csh、tcsh、zsh、python(?!?!!)等。

Another option is to use "Environment Modules" (http://modules.sourceforge.net/). This unfortunately introduces a third language into the mix. You define the environment with the language of Tcl, but there are a few handy commands for typical modifications (prepend vs. append vs set). You will also need to have environment modules installed. You can then use module load *XXX* to name the environment you want. The module command is basically a fancy alias for the eval mechanism described above by Thomas Kammeyer. The main advantage here is that you can maintain the environment in one language and rely on "Environment Modules" to translate it to sh, ksh, bash, csh, tcsh, zsh, python (?!?!!), etc.

晚风撩人 2024-07-20 03:55:39

我使用管道、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

它可能适用于任何命令。

I created a solution using pipes, eval and signal.

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

It might work with any command.

煮酒 2024-07-20 03:55:39

我没有看到任何答案记录如何通过合作流程解决此问题。 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;

(这会导致代理开始运行,但不允许您实际使用它,除非您现在将此输出复制粘贴到 shell 提示符中。)比较:(

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 脚本将简单地计算并打印该值,并让调用者用它做任何他们想做的事情——将它分配给变量是一个常见的用例,但可能不是你想要硬做的事情 -将代码写入产生值的工具中。

I don't see any answer documenting how to work around this problem with cooperating processes. A common pattern with things like ssh-agent is to have the child process print an expression which the parent can eval.

bash$ eval $(shh-agent)

For example, ssh-agent has options to select Csh or Bourne-compatible output syntax.

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;

(This causes the agent to start running, but doesn't allow you to actually use it, unless you now copy-paste this output to your shell prompt.) Compare:

bash$ ssh-agent -c
setenv SSH2_AUTH_SOCK /tmp/ssh-era/ssh2-10751-agent;
setenv SSH2_AGENT_PID 10752;
echo Agent pid 10752;

(As you can see, csh and tcsh uses setenv to set varibles.)

Your own program can do this, too.

bash$ foo=$(makefoo)

Your makefoo script would simply calculate and print the value, and let the caller do whatever they want with it -- assigning it to a variable is a common use case, but probably not something you want to hard-code into the tool which produces the value.

趴在窗边数星星i 2024-07-20 03:55:39

这不是我所说的杰出,但如果您无论如何都需要从 shell 调用脚本,这也可以工作。 这不是一个好的解决方案,但对于单个静态环境变量来说,它已经足够好了。

1.) 创建一个脚本,其退出条件为 0(成功)或 1(不成功)

if [[ $foo == "True" ]]; then
    exit 0
else
    exit 1

2.) 创建一个依赖于退出代码的别名。

alias='myscript.sh && export MyVariable'

您调用别名,该别名调用脚本,该脚本评估条件,需要通过“&&”退出零 为了在父 shell 中设置环境变量。

这是废物,但在紧要关头还是有用的。

It's not what I would call outstanding, but this also works if you need to call the script from the shell anyway. It's not a good solution, but for a single static environment variable, it works well enough.

1.) Create a script with a condition that exits either 0 (Successful) or 1 (Not successful)

if [[ $foo == "True" ]]; then
    exit 0
else
    exit 1

2.) Create an alias that is dependent on the exit code.

alias='myscript.sh && export MyVariable'

You call the alias, which calls the script, which evaluates the condition, which is required to exit zero via the '&&' in order to set the environment variable in the parent shell.

This is flotsam, but it can be useful in a pinch.

冰雪梦之恋 2024-07-20 03:55:39

从技术上讲,这是正确的——只有“eval”不会派生另一个 shell。 但是,从您尝试在修改后的环境中运行的应用程序的角度来看,差异为零:子级继承其父级的环境,因此(修改后的)环境将传递给所有下行进程。

事实上,只要您在父程序/shell 下运行,更改后的环境变量就会“保留”。

如果在父级(Perl 或 shell)退出后环境变量绝对有必要保留,则父级 shell 必须承担繁重的工作。 我在文档中看到的一种方法是让当前脚本使用必要的“导出”语言生成一个可执行文件,然后欺骗父 shell 执行它——始终认识到您需要在如果您试图保留已修改环境的非易失性版本,请使用带有“source”的命令。 充其量是克鲁格。

第二种方法是修改启动 shell 环境(.bashrc 或其他)的脚本以包含修改后的参数。 这可能很危险——如果您使用初始化脚本,它可能会使您的 shell 下次尝试启动时不可用。 有很多工具可以修改当前的 shell; 通过对“启动器”进行必要的调整,您也可以有效地推动这些更改。
一般来说这不是一个好主意; 如果您只需要更改特定应用程序套件的环境,则之后必须返回并将 shell 启动脚本返回到其原始状态(使用 vi 或其他方式)。

简而言之,没有好的(且简单的)方法。 据推测,这是为了确保系统的安全性不会受到不可挽回的损害而变得困难。

Technically, that is correct -- only 'eval' doesn't fork another shell. However, from the point of view of the application you're trying to run in the modified environment, the difference is nil: the child inherits the environment of its parent, so the (modified) environment is conveyed to all descending processes.

Ipso facto, the changed environment variable 'sticks' -- as long as you are running under the parent program/shell.

If it is absolutely necessary for the environment variable to remain after the parent (Perl or shell) has exited, it is necessary for the parent shell to do the heavy lifting. One method I've seen in the documentation is for the current script to spawn an executable file with the necessary 'export' language, and then trick the parent shell into executing it -- always being cognizant of the fact that you need to preface the command with 'source' if you're trying to leave a non-volatile version of the modified environment behind. A Kluge at best.

The second method is to modify the script that initiates the shell environment (.bashrc or whatever) to contain the modified parameter. This can be dangerous -- if you hose up the initialization script it may make your shell unavailable the next time it tries to launch. There are plenty of tools for modifying the current shell; by affixing the necessary tweaks to the 'launcher' you effectively push those changes forward as well.
Generally not a good idea; if you only need the environment changes for a particular application suite, you'll have to go back and return the shell launch script to its pristine state (using vi or whatever) afterwards.

In short, there are no good (and easy) methods. Presumably this was made difficult to ensure the security of the system was not irrevocably compromised.

赠佳期 2024-07-20 03:55:39

简短的答案是否定的,您无法更改父进程的环境,但似乎您想要的是一个具有自定义环境变量和用户选择的 shell 的环境。

那么,为什么不简单地执行类似

#!/usr/bin/env bash
FOO=foo $SHELL

“Then”这样的操作,当您完成环境后,只需 exit 即可。

The short answer is no, you cannot alter the environment of the parent process, but it seems like what you want is an environment with custom environment variables and the shell that the user has chosen.

So why not simply something like

#!/usr/bin/env bash
FOO=foo $SHELL

Then when you are done with the environment, just exit.

甜尕妞 2024-07-20 03:55:39

您始终可以使用别名

alias your_env='source ~/scripts/your_env.sh'

You could always use aliases

alias your_env='source ~/scripts/your_env.sh'
万劫不复 2024-07-20 03:55:39

我很多年前就这么做过。 如果我没记错的话,我在 .bashrc 和 .cshrc 中都包含了一个带有参数的别名,将设置环境的相应形式别名为通用形式。

然后,您将在两个 shell 中的任何一个中获取的脚本都有一个采用最后一种形式的命令,该命令在每个 shell 中都有合适的别名。

如果我找到具体的别名,我会发布它们。

I did this many years ago. If I rememeber correctly, I included an alias in each of .bashrc and .cshrc, with parameters, aliasing the respective forms of setting the environment to a common form.

Then the script that you will source in any of the two shells has a command with that last form, that is suitable aliased in each shell.

If I find the concrete aliases, I will post them.

生死何惧 2024-07-20 03:55:39

除了取决于 $SHELL/$TERM 设置的写入条件之外,没有。 使用 Perl 有什么问题? 它非常普遍(我想不出哪个 UNIX 变体没有它),而且它会帮你省去麻烦。

Other than writings conditionals depending on what $SHELL/$TERM is set to, no. What's wrong with using Perl? It's pretty ubiquitous (I can't think of a single UNIX variant that doesn't have it), and it'll spare you the trouble.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文