如何在sh脚本中运行csh脚本

5

我想知道是否有一种方法可以从sh脚本中调用csh脚本。下面是一个尝试实现的示例:

script1.sh:

#!/bin/sh

source script2

脚本2:

#!/bin/csh -f

setenv TEST 1234
set path = /home/user/sandbox

当我运行sh script1.sh时,我会从script2中生成语法错误(因为我们正在使用不同的Shebang,所以这是预期的)。有没有办法通过script1运行script2?
5个回答

6

不要使用source script2,改为以下方式运行:

csh -f script2

2

由于您的用例依赖于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 可以确保当 script1csh 实例重新执行时不会陷入循环中。
不幸的是,我认为至少通过我的有限的 csh 知识,有一个缺点是无法修复的:第二次调用 script1 会将所有原始参数作为单个字符串接收,而不是一系列不同的参数。

1
您不需要在那里使用source;它会在现有的shell中运行给定的脚本,而不会产生子进程。显然,您的sh进程无法运行像那样不是sh脚本的内容。
只需直接调用该脚本,假设它是可执行的:
script2

1
最接近使用不同执行器源代码的方法是使用execexec将用新进程替换运行进程空间。然而,与source不同的是,当exec程序结束时,整个进程也会结束。因此,您可以这样做:
#!/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

感谢您的详细解答。在阅读了您的回答后,我意识到我原本想要将其作为子进程来执行。请原谅我的匆忙,我还在适应发布的过程中。 - user3245776

0

你想让在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脚本中进行源引用,另一个用于从sh/ksh/bash/zsh脚本中进行源引用或点操作,这是不切实际的,那么就有其他解决方案。例如,您的脚本可以打印一系列要执行的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可能不是一个好主意。它会用单个目录替换整个$PATH,这意味着您将无法执行简单的命令,如ls,除非您指定其完整路径。通常您需要像这样的东西:

set path = ( $path /home/user/sandbox )

或者,在 sh 中:

PATH=$PATH:/home/user/sandbox

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接