我试图编写一个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的变量时,它们会
继承副本本身。
您可以做的一件事是编写一个脚本,为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新闻服务器中也有类似的功能。
从技术上讲,这是正确的——只有'eval'不会派生另一个shell。然而,从您试图在修改后的环境中运行的应用程序的角度来看,差异为零:子进程继承其父进程的环境,因此(修改后的)环境被传递给所有下行进程。
事实上,只要你在父程序/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.
简而言之,没有好的(简单的)方法。想必这很难确保系统的安全性不会受到不可挽回的损害。