&引用;资料来源;在ruby子壳中
我需要从ruby应用程序运行shell命令。我使用的是&引用;资料来源;在ruby子壳中,ruby,shell,Ruby,Shell,我需要从ruby应用程序运行shell命令。我使用的是system(),但这也适用于反勾号 在运行命令时,我需要首先加载一个shell脚本来设置一些内容,因此我尝试以下方法: system("source my_script.sh && my_command") 在我的Mac笔记本电脑上,这可以按预期工作,但在我的ubuntu服务器上,我得到: sh: 1: source: not found 我想知道其中的“sh”,因为我的shell应该是bash,所以尝试了以下方法: s
system()
,但这也适用于反勾号
在运行命令时,我需要首先加载一个shell脚本来设置一些内容,因此我尝试以下方法:
system("source my_script.sh && my_command")
在我的Mac笔记本电脑上,这可以按预期工作,但在我的ubuntu服务器上,我得到:
sh: 1: source: not found
我想知道其中的“sh”,因为我的shell应该是bash,所以尝试了以下方法:
system("echo $SHELL && source my_script.sh && my_command")
这给了我:
/bin/bash
sh: 1: source: not found
因此,它使用的是正确的shell,但出于某种原因,source
不起作用
为什么??我能做些什么呢
更新
正如Sergio Tulentsev指出的,Ruby不一定使用$shell中设置的shell
这给了我ruby实际使用的shell:
system("ps -p $$ | tail -1 | awk '{print $NF}'")
sh
=> true
因此,它使用的是sh。我可以强制它使用bash吗?您需要尝试在要源文件的前面添加
/
,如果子SHELL是bash,这应该可以工作(选中$SHELL
)
如果
$SHELL
是sh
,则需要执行/test.sh
而不是source./test.sh
,因为source关键字仅为bash
或者,您可以通过执行以下操作来确保您正在使用bash:
irb(main):007:0> system("/bin/bash -c 'source ./test.sh && echo $TEST && cat test.sh'")
test
export TEST=test
=> true
正如其他人所指出的,Ruby使用
sh
作为其子shell。使用bash的一种方法是类似于system(“/bin/bash-c'…”)
,这会导致各种转义问题。相反,我决定使用Open3生成一个“真正的”进程,在其中运行bash并将我的命令导入其中。工作起来很有魅力:
require "open3"
# using bash --login to ensure the same env as usual
Open3.popen3('/usr/bin/env bash --login') do |stdin, stdout, stderr, wait_thr|
pid = wait_thr[:pid]
stdin.puts("cd some_directory")
stdin.puts("source some_script")
stdin.puts("some_command")
# don't forget to close it again
stdin.puts("exit")
# for debug purposes
stdout.each_line do |line|
puts "STDOUT: " + line
end
stdin.close
stdout.close
stderr.close
end
这看起来有点过分,但它允许对子进程的控制实际上是非常好的
谢谢大家的建议。如果
$SHELL
设置为bash,我想这并不一定意味着ruby会使用它。试试这个技巧来确定实际的外壳:哦,我不知道。但是是的,它实际上是“sh”。谢谢。如果$SHELL
是sh
,那么源代码
将无法工作,您需要反编译。file.sh
来获取它的源代码不是这样的。即使使用绝对路径,它也不起作用。谢谢,这种方法很有效,但会让我逃避命令字符串的问题。我想我将使用Open3生成/usr/bin/env bash
,以更好地控制它。这听起来是个好主意。至于转义,您可能应该包装您的Open3调用,所以它会处理这个问题。您对转义问题有很好的看法。但是你展示的代码也展示了那些逃避问题,不是吗?当我所做的只是将命令放在stdin上时,我不知道如何通过数组获得安全转义命令语法。也许我错过了什么。
require "open3"
# using bash --login to ensure the same env as usual
Open3.popen3('/usr/bin/env bash --login') do |stdin, stdout, stderr, wait_thr|
pid = wait_thr[:pid]
stdin.puts("cd some_directory")
stdin.puts("source some_script")
stdin.puts("some_command")
# don't forget to close it again
stdin.puts("exit")
# for debug purposes
stdout.each_line do |line|
puts "STDOUT: " + line
end
stdin.close
stdout.close
stderr.close
end