我想知道是否有一种方法可以从sh脚本中获取csh脚本。下面是一个尝试实现的示例:
script1.sh:
#!/bin/sh
source script2
script2:
#!/bin/csh -f
setenv TEST 1234
set path = /home/user/sandbox
当我运行sh script1.sh时,我会收到从script2生成的语法错误(由于我们使用的是不同的Shebang,所以会出现这种情况)。有没有一种方法可以让script2运行到script1?
将其作为:运行,而不是source script2
csh -f script2
由于您的用例依赖于保留csh
脚本设置的环境变量,请尝试将其添加到script1
:的开头
#!/bin/sh
if [ "$csh_executed" -ne 1 ]; then
csh_executed=1 exec csh -c "source script2;
exec /bin/sh "$0" "$argv"" "$@"
fi
# rest of script1
如果环境中的csh_executed
变量未设置为1,则运行csh
脚本,该脚本源于script2
,然后执行sh
的实例,该实例将保留在script2
中对环境所做的更改。exec
用于避免为每个shell实例创建新进程,而只是从一个shell"切换"到下一个shell。在csh
命令的环境中设置csh_executed
可以确保当csh
实例重新执行script1
时,我们不会陷入循环。
不幸的是,有一个缺点我认为是无法修复的,至少在我对csh
的有限了解下是无法修复:script1
的第二次调用将所有原始参数作为单个字符串接收,而不是作为一系列不同的参数。
您不希望source
在那里;它在现有shell中运行给定的脚本,而不生成子流程。显然,您的sh进程不能运行类似的非sh脚本的程序。
只要直接调用脚本,假设它是可执行的:
script2
您最接近使用与原始脚本不同的执行器来寻找脚本的方法是使用exec
。exec
将用新进程替换正在运行的进程空间。然而,与source
不同的是,当exec
-ed程序结束时,整个过程就结束了。所以你可以这样做:
#!/bin/sh
exec /path/to/csh/script
但你不能这样做:
#!/bin/sh
exec /path/to/csh/script
some-other-command
但是,您确定要源代码脚本吗?也许你只是想在一个子流程中运行它:
#!/bin/sh
csh -f /path/to/csh/script
some-other-command
您希望csh脚本中的设置应用于调用它的sh脚本。
基本上,你不能这样做,尽管有一些(相当丑陋的)方法可以让它发挥作用。如果执行csh脚本,它将在运行脚本的进程的上下文中设置这些变量;一旦它返回给调用者,它们就会消失。
最好的办法是简单地将csh脚本的新版本编写为sh脚本,并从调用sh脚本中编写source
或.
。
你可以翻译你的csh脚本:
#!/bin/csh -f
setenv TEST 1234
set path = /home/user/sandbox
到此:
export TEST=1234
export PATH=/home/user/sandbox
(csh专门处理shell数组变量$path
,将其与环境变量$PATH
绑定。sh及其衍生物不这样做,而是直接处理$PATH
本身。)
请注意,要来源的脚本不应该在顶部有#!
行,因为在自己的进程中执行它是没有意义的;您需要在调用者的上下文中执行它的内容。
如果维护脚本的两个副本,一个是csh或tcsh脚本中的source
d,另一个是sh/ksh/bash/zsh脚本中的source
d或.
ed,这是不可行的,还有其他解决方案。例如,您的脚本可以打印一系列要执行的sh
命令;然后你可以做一些类似的事情
eval `./foo.csh`
(这里的行尾会带来一些问题)。
或者,您可以修改csh脚本,使其设置所需的环境变量,然后调用一些指定的命令,该命令可以是一个新的交互式shell;这很不方便,因为它不会在您运行的交互式shell中设置这些变量。
如果软件包需要设置一些特殊的环境变量,通常的做法是提供名为setup.sh
和setup.csh
的脚本,以便sh/ksh/bash/zsh用户可以执行以下操作:
. /path/to/package/setup.sh
csh/tcsh用户可以做:
source /path/to/package/setup.csh
顺便说一句,这个命令:
set path = /home/user/sandbox
在您的示例脚本中可能不是一个好主意。它将整个$PATH
替换为一个目录,这意味着除非指定它们的完整路径,否则您将无法执行像ls
这样的简单命令。你通常想要这样的东西:
set path = ( $path /home/user/sandbox )
或者,以sh:表示
PATH=$PATH:/home/user/sandbox