如何在 bash 中获取 csh 脚本来设置环境 [关闭]

Posted

技术标签:

【中文标题】如何在 bash 中获取 csh 脚本来设置环境 [关闭]【英文标题】:how to source a csh script in bash to set the environment [closed] 【发布时间】:2011-02-12 05:43:57 【问题描述】:

我们在 Solaris 上运行 Oracle,shell 默认为 csh。所以登录脚本也会在 csh 中设置 oracle_home、oracle_sid。但是我不喜欢 csh 并且想使用 bash 来完成我的工作。那么如何在bash中获取csh登录脚本呢?

例如,以下是 .cshrc 文件中的内容。当使用 bash 时,我想使用这些变量。一种方法是再次复制变量并使用 bash 命令,例如 export ORACLE_SID=TEST。但是这样做需要我们维护两个文件的副本。而当我们更改数据库名称,或者升级数据库时,我需要单独维护 bash 登录文件。使用类似的东西很好

在 bash 中输入 .cshr,但它不起作用。

setenv ORACLE_SID 测试 setenv ORACLE_HOME /oracle/TEST/home/products/10204 setenv EPC_DISABLED TRUE setenv MANPATH /usr/local/man:/usr/share/man setenv 编辑器 vi setenv LD_LIBRARY_PATH $ORACLE_HOME/lib:/usr/sfw/lib/64 setenv NLS_LANG AMERICAN_AMERICA.UTF8 setenv NLS_DATE_FORMAT "DD-MON-RR"

【问题讨论】:

更适合超级用户或服务器故障? 【参考方案1】:

有一个可用的模块,您可以通过它在 perl 脚本中的任意位置获取相同的文件。您将在您的 csh 文件中获得所有可用的环境路径。

Source::Shell

通过一些文档了解它的用法。

【讨论】:

【参考方案2】:

对于这么小的东西,通常维护两个设置脚本,一个用于 sh 和 sh 派生的 shell,一个用于 csh 和 tcsh。正如您所提到的,这确实会产生两个脚本不同步的风险——除非您从另一个生成一个,或者从一个共同的来源生成两个。

这将负担放在了设置脚本的维护者身上,而不是每个需要使用它们的用户身上。

【讨论】:

【参考方案3】:

只需在 CSH 脚本的开头提供“#!/bin/tcsh”或类似的语句,同时使脚本可执行,就可以解决我的问题。在这种情况下,我可以直接从 bash 调用 CSH 脚本。

例如,我必须从名为 setup.sh 的 bash 脚本运行 tools.csh。我在 bash 脚本中做了这样的事情:

if [ -z \`head -1 tools.csh | grep '^#!'\` ];
then
   TCSH=\`which tcsh\`;
   echo "'#!'$TCSH" > tools.csh.temp;
   cat tools.csh >> tools.csh.temp;
   mv tools.csh.temp tools.csh;
fi;
chmod 755 tools.csh;
./tools.csh
# now I have all the setenv commands effective ...

【讨论】:

如果./tools.csh 设置了环境变量,它们不会在调用shell 中可见。如果依赖于那些环境变量的命令都在./tools.csh,那没关系。【参考方案4】:

我在同一条船上。一位同事向我展示了以下内容:

从 bash 开始,没有 thwe 环境中的东西:

bash> echo $$
12632
bash> echo $FOO

这是获取源代码的 csh 文件:

bash> cat setup-env.csh
setenv FOO "some csh stuff"
echo FOO=$FOO in csh

命令如下:

bash> csh -c 'source setup-env.csh;exec bash'

查看 csh 的输出

FOO=some csh stuff in csh

然后查看新 bash shell 的输出

  bash> echo $$
  13487
  bash> echo $FOO
  some csh stuff

现在离开,回到原来的 bash shell

bash> exit
exit
bash> echo $$
12632
bash> 

注意 echo $$ 以查看进程 ID,以便我们可以看到它们是不同的 shell 进程。

我的同事使用这个足够多,他将其放入别名中,例如:

# make csh environment scripts useable (sourceable) from bash function 
# from Phil McCoy, Wed Nov  9 2011
source_csh () 
   exec csh -c " source $*; setenv ALREADY_SOURCED \"$ALREADY_SOURCED:$*:\"; exec bash"

# sounds like a great idea to do source_csh .cshrc or .login
# but naively done is infinitely recursive, 
# since the exec'ed bash will run .bashrc

不幸的是,我发现我经常不仅需要设置环境变量,还需要设置别名,例如模块包http://modules.sourceforge.net/。

我已经能够通过使用 Perl Expect 来自动化这个“csh 源脚本配方”。但除了上述之外,我还不能像我想要的那样互动。

【讨论】:

我是 modules 包的忠实粉丝,我很惊讶越来越多的人不使用它。让事情与外壳无关只是一件好事。【参考方案5】:

像这样定义一个名为 setenv 的函数怎么样

setenv() 
  echo setting $1 to $2
  export $1=$2

然后获取 .cshrc 文件。

当我在 bash 中执行此操作时,我得到了

[dws@oxygen ual-read-only]$ source cshrc
setting ORACLE_SID to TEST
setting ORACLE_HOME to /oracle/TEST/home/products/10204
setting EPC_DISABLED to TRUE
setting MANPATH to /usr/local/man:/usr/share/man
setting EDITOR to vi
setting LD_LIBRARY_PATH to /oracle/TEST/home/products/10204/lib:/usr/sfw/lib/64
setting NLS_LANG to AMERICAN_AMERICA.UTF8
setting NLS_DATE_FORMAT to DD-MON-RR
[dws@oxygen ual-read-only]$ env | grep ORACLE
ORACLE_SID=TEST
ORACLE_HOME=/oracle/TEST/home/products/10204

【讨论】:

关闭但没有雪茄。 (1) 一些 csh 源脚本设置别名 - 我不知道如何将别名从 csh 导出回调用 shell,如 bash。我想将任何 csh 别名转换为 bash 别名只是一个简单的编程问题,反之亦然(后者用于调用新的 csh 源脚本)。 (2) 由于我的普通登录 shell 有额外的环境变量,我需要先清空它。这就是我要问的。 (3),哦,刚刚注意到你在做什么:是的,我已经在 bash 中有一个 setenv 多年了。 (实际上,在 bash 存在之前,在 ksh 中。)【参考方案6】:

在您的~/.bashrc(或存在的~/.bash_profile~/.bash_login~/.profile 中的第一个)中,使用. ~/bin/sourcecsh 之类的方式获取此脚本:

#!/bin/bash
# This should be sourced rather than executed
while read cmd var val
do
    if [[ $cmd == "setenv" ]]
    then
        eval "export $var=$val"
    fi
done < ~/.cshrc

此版本除恶eval

#!/bin/bash
# This should be sourced rather than executed
# yes, it will be sourcing within sourcing - what so(u)rcery!
source /dev/stdin < \
<(
    while read cmd var val
    do
        if [[ $cmd == "setenv" ]]
        then
             echo "export $var=$val"
        fi
    done < cshrc
)

编辑:

没有采购标准输入:

while read cmd var val
do
    if [[ $cmd == "setenv" ]]
    then
        declare -x "$var=$val"
    fi
done < cshrc

【讨论】:

@Dennis - 不错...我喜欢这个,因为它是纯粹的 bash(我的使用 sed)...我必须承认我仍然更喜欢我的版本(相当相似),因为它保持设置命令列表作为文件用于以后的故障排除或环境恢复以防万一:) 我会投票给第一个版本——采购标准输入至少和eval 一样容易出问题。【参考方案7】:

在您的 bash .profile 中,您可以执行以下操作:

cat .cshrc | sed 's/setenv\s+(\S+)\s+(.*)$/set $1=$2; export $1/' > $HOME/.env_from_csh
source $HOME/.env_from_csh

【讨论】:

这也很酷,我不喜欢创建一些垃圾文件。不确定我们是否可以只使用管道来避免临时文件。 cat 的无用使用。 Bash 不会那样使用setexport 可以同时获取变量名和赋值。您必须使用不同版本的sed,因为它看起来像 Perl 语法。您需要使用-r 或转义括号和加号。您可以像这样消除临时文件:source /dev/stdin &lt; &lt;(sed 's/setenv\s\+\(\S\+\)\s\+\(.*\)$/export \1=\2/' .cshrc) @Dennis 和 Daniel - 我通常想要那个“垃圾”临时文件:) source /dev/stdin &lt; &lt;(sed 's/setenv\s\+\(\S\+\)\s\+\(.*\)$/export \1=\2/' .cshrc | tee $HOME/.env_from_csh)【参考方案8】:

在 bash 中获取 csh 文件将不起作用。如果您在 bash 中更舒适,可以将默认登录 shell 从 csh 更改为 bash。您可以使用 chsh 或以管理员身份为您更改。

chsh -s /usr/local/bin/bash 

【讨论】:

【参考方案9】:

我能想到的唯一方法是加载 csh 然后从那个新的 shell 调用 bash。这样 csh 可以解析该文件,然后它产生的 bash 也将继承该环境。

【讨论】:

在代码中:(cat .cshrc; echo exec $SHELL) | csh

以上是关于如何在 bash 中获取 csh 脚本来设置环境 [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

如何编写 bash 脚本来设置全局环境变量?

如何为 csh/tcsh 中的一个命令设置环境变量

当我获取 bash 脚本时,$0 不起作用

bash和 csh 区别

Shell第一篇:BASH 环境

shell脚本命令格式注意点