我想知道是否有办法从sh脚本中获取csh脚本。以下是尝试实施的示例:
script1.sh:
#!/bin/sh
source script2
SCRIPT2:
#!/bin/csh -f
setenv TEST 1234
set path = /home/user/sandbox
当我运行sh script1.sh时,我得到了脚本2生成的语法错误(预计因为我们使用的是另一个Shebang)。有没有办法可以通过script1运行script2?
答案 0 :(得分:5)
而不是source script2
将其视为:
csh -f script2
答案 1 :(得分: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_executed
命令的环境中设置csh
可确保在script1
实例重新执行csh
时不会陷入循环。
不幸的是,有一个缺点,我认为不能修复,至少不是我对csh
的有限知识:script1
的第二次调用接收所有原始参数作为单个字符串,而不是一系列不同的参数。
答案 2 :(得分:1)
你不希望source
在那里;它在现有shell中运行给定脚本,而不会生成子进程。显然,你的sh进程不能运行那些不是sh脚本的东西。
直接调用脚本,假设它是可执行的:
script2
答案 3 :(得分:0)
您最接近 sourcing 使用与原始脚本不同的执行程序的脚本的方法是使用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
答案 4 :(得分: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脚本的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