当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《shell脚本可以设置调用shell的环境变量吗?》经验,为你挑选了8个好方法。

我正在尝试编写一个shell脚本,在运行时,将设置一些将在调用者的shell中保留的环境变量.

setenv FOO foo

在csh/tcsh中,或

export FOO=foo

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

我已经知道了

source myscript

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

但这里有一个问题:

我希望这个脚本可以从bash或csh调用.换句话说,我希望任何一个shell的用户都能够运行我的脚本并改变他们的shell环境.所以'source'对我来说不起作用,因为运行csh的用户无法获取bash脚本,而运行bash的用户无法获取csh脚本.

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



1> 小智..:

使用"点空间脚本"调用语法.例如,以下是如何使用脚本的完整路径来完成它:

. /path/to/set_env_vars.sh

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

. set_env_vars.sh

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

这与调用相同source set_env_vars.sh,但是键入的时间更短,并且可能在某些source没有调用的地方工作.


换句话说,点空间是其他shell中bash的`source`的替代品.
这个答案应该在顶部
我不知道它是如何或为什么有效,但它完美无缺.
吉普应该在顶部.只是陈述显而易见的..如果脚本在你的PWD中,那么它具有点空间点的形式,例如../localscript.sh
我注意到如果有人输出输出,这将无法工作,例如"./script.sh | tee out.log"

2> converter42..:

您的shell进程具有父级环境的副本,并且无法访问父进程的环境.当shell进程终止时,您对其环境所做的任何更改都将丢失.获取脚本文件是配置shell环境最常用的方法,您可能只想咬住子弹并为两种shell中的每一种维护一个.



3> Thomas Kamme..:

您无法修改调用者的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新闻服务器中也有类似的功能.


SHELL变量并非完全可靠.示例:在我的ArchLinux系统上运行tcsh,SHELL设置为/ bin/tcsh.启动bash并回显SHELL仍然给/ bin/tcsh和ditto调用bash作为sh.SHELL仅适用于需要设置它的shell或使用设置它的rc文件的系统,而不是全部都可以.

4> 小智..:

在我的.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中运行,并按预期和需要设置变量.



5> Kjetil Joerg..:

通过使用gdb和setenv(3)可以"有点" ,虽然我很难推荐实际做到这一点.(另外,即最近的ubuntu实际上不会让你这样做而不告诉内核对ptrace更加宽容,同样可能也适用于其他发行版).

$ cat setfoo
#! /bin/bash

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

$ ./setfoo
$ echo $foo
bar



6> Jonathan Lef..:

这有效 - 它不是我使用的,但它"有效".让我们创建一个脚本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可用作一般的"设置环境和执行命令"工具.您可能想要省略-iif是否有其他参数,导致:

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

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


毫无疑问 - 这就是为什么我说我不会用它.如果你执行两次,你没有丢失会话或进程组信息; 这是基于PID和PID不会改变.在配置文件或登录文件中,它将引导您完成公共语言环境设置脚本.但是,正如我所说,我不会使用它.

7> Davide..:

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

编辑:自2012年以来,模块包尚未更新,但仍然适用于基础知识.所有新功能,铃声和口哨都发生在今天的lmod中(我更喜欢它):https://www.tacc.utexas.edu/research-development/tacc-projects/lmod



8> dkinzer..:

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

我遇到了一个非常类似的问题,我想能够运行最后一次设置测试(而不是我所有的测试).我的第一个计划是编写一个用于设置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

推荐阅读
爱唱歌的郭少文_
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有