如何从sh脚本运行csh脚本



我想知道是否有一种方法可以从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

您最接近使用与原始脚本不同的执行器来寻找脚本的方法是使用execexec将用新进程替换正在运行的进程空间。然而,与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脚本中的sourced,另一个是sh/ksh/bash/zsh脚本中的sourced或.ed,这是不可行的,还有其他解决方案。例如,您的脚本可以打印一系列要执行的sh命令;然后你可以做一些类似的事情

eval `./foo.csh`

(这里的行尾会带来一些问题)。

或者,您可以修改csh脚本,使其设置所需的环境变量,然后调用一些指定的命令,该命令可以是一个新的交互式shell;这很不方便,因为它不会在您运行的交互式shell中设置这些变量。

如果软件包需要设置一些特殊的环境变量,通常的做法是提供名为setup.shsetup.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

相关内容

  • 没有找到相关文章

最新更新