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

setenv FOO foo

在csh/tcsh中,或

export FOO=foo

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

我已经知道了

source myscript

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

但问题是:

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

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


当前回答

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

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

如果我找到具体的化名,我会公布的。

其他回答

除了根据$SHELL/$TERM设置的写入条件外,没有。使用Perl有什么问题?它非常普遍(我想不出有哪个UNIX变体没有它),而且它将为您省去这些麻烦。

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

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

在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的变量时,它们会 继承副本本身。

您可以做的一件事是编写一个脚本,为tcsh发出正确的命令 或者基于调用方式的sh。如果你的脚本是“setit”,那么执行:

ln -s setit setit-sh

and

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新闻服务器中也有类似的功能。