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

setenv FOO foo

在csh/tcsh中,或

export FOO=foo

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

我已经知道了

source myscript

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

但问题是:

我希望这个脚本可以从bash或csh中调用。换句话说,我希望任何一个shell的用户都能够运行我的脚本,并更改他们的shell环境。因此,'source'对我来说不适用,因为运行csh的用户不能获取bash脚本的源代码,而运行bash的用户也不能获取csh脚本的源代码。

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


当前回答

您的shell进程拥有父进程环境的副本,并且不能访问父进程的任何环境。当您的shell进程终止时,您对其环境所做的任何更改都将丢失。获取脚本文件是配置shell环境最常用的方法,您可能只想咬紧牙关,为两种shell类型各维护一个脚本文件。

其他回答

我创建了一个解决方案使用管道,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

它可能适用于任何命令。

在OS X bash下,您可以执行以下操作: 创建bash脚本文件以取消该变量的设置

#!/bin/bash
unset http_proxy

使文件可执行

sudo chmod 744 unsetvar

创建别名

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

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

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

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

您的shell进程拥有父进程环境的副本,并且不能访问父进程的任何环境。当您的shell进程终止时,您对其环境所做的任何更改都将丢失。获取脚本文件是配置shell环境最常用的方法,您可能只想咬紧牙关,为两种shell类型各维护一个脚本文件。

使用“点空格脚本”调用语法。例如,下面是如何使用脚本的完整路径:

. /path/to/set_env_vars.sh

如果你和脚本在同一个目录中,下面是如何做到这一点:

. set_env_vars.sh

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

这与调用源set_env_vars.sh是一样的事情,但它的输入更短,并且可能在源不能工作的某些地方工作。