我想知道是否有一种方法可以从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?
不要使用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
可以确保当 script1
被 csh
实例重新执行时不会陷入循环中。
csh
知识,有一个缺点是无法修复的:第二次调用 script1
会将所有原始参数作为单个字符串接收,而不是一系列不同的参数。source
;它会在现有的shell中运行给定的脚本,而不会产生子进程。显然,您的sh进程无法运行像那样不是sh脚本的内容。script2
exec
。exec
将用新进程替换运行进程空间。然而,与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
你想让在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.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
可能不是一个好主意。它会用单个目录替换整个$PATH
,这意味着您将无法执行简单的命令,如ls
,除非您指定其完整路径。通常您需要像这样的东西:
set path = ( $path /home/user/sandbox )
或者,在 sh 中:
PATH=$PATH:/home/user/sandbox