我想bash
从一个执行一些命令Rakefile
.
我在我的尝试中尝试了以下内容 Rakefile
task :hello do
%{echo "World!"}
end
Run Code Online (Sandbox Code Playgroud)
但在执行rake hello
时没有输出?如何从Rakefile执行bash命令?
注意:这不是重复,因为它具体询问如何从Rakefile执行bash命令.
Giz*_*wai 121
我认为rake希望这种情况发生的方式是:http://rubydoc.info/gems/rake/FileUtils#sh-instance_method 示例:
task :test do
sh "ls"
end
Run Code Online (Sandbox Code Playgroud)
内置rake函数sh负责命令的返回值(如果命令的返回值不是0,则任务失败),此外它还输出命令输出.
Ben*_*Lee 58
有几种方法可以在ruby中执行shell命令.一个简单的(可能是最常见的)是使用反引号:
task :hello do
`echo "World!"`
end
Run Code Online (Sandbox Code Playgroud)
反引号具有很好的效果,其中shell命令的标准输出变为返回值.因此,例如,您可以ls
通过执行获得输出
shell_dir_listing = `ls`
Run Code Online (Sandbox Code Playgroud)
但是还有许多其他方法可以调用shell命令,它们都有优点/缺点并且工作方式不同.本文详细解释了这些选择,但这里有一个快速概述的可能性:
stdout =%x {cmd} - 反叛的替代语法,幕后它正在做同样的事情
exec(cmd) - 使用新的cmd进程完全替换正在运行的进程
success = system(cmd) - 运行子进程并在成功/失败时返回true/false(基于cmd退出状态)
IO#popen(cmd){| io | } -运行一个子进程,并连接输出和错误木卫一
stdin,stdout,stderr = Open3.popen3(cmd) - 运行子进程并连接到所有管道(in,out,err)
%{echo "World!"}
定义一个字符串。我希望你想要%x{echo "World!"}
。
%x{echo "World!"}
执行命令并返回输出 (stdout)。你不会看到结果。但你可以这样做:
puts %x{echo "World!"}
Run Code Online (Sandbox Code Playgroud)
还有更多调用系统命令的方法:
system( cmd )
popen
Open3#popen3
鉴于共识似乎更喜欢rake的#sh
方法,但是OP明确要求使用bash,因此此答案可能会有用。
这很重要,因为Rake#sh
使用Kernel#system
调用来运行shell命令。Ruby将其硬编码为/bin/sh
,而忽略了用户配置的外壳程序或$SHELL
环境中的内容。
这是一种从调用bash的解决方法/bin/sh
,使您仍然可以使用sh
方法:
task :hello_world do
sh <<-EOS.strip_heredoc, {verbose: false}
/bin/bash -xeuo pipefail <<'BASH'
echo "Hello, world!"
BASH
EOS
end
class String
def strip_heredoc
gsub(/^#{scan(/^[ \t]*(?=\S)/).min}/, ''.freeze)
end
end
Run Code Online (Sandbox Code Playgroud)
#strip_heredoc
从rails借来的:
https://github.com/rails/rails/blob/master/activesupport/lib/active_support/core_ext/string/strip.rb
您可能可以通过需要active_support来获得它,或者当您在Rails项目中时可以自动加载它,但是我使用的是外部Rails,因此必须自己定义它。
这里有两个heredocs,一个带有标记的外部文档EOS
和一个带有标记的内部文档BASH
。
这种工作方式是通过将BASH标记之间的内部Heredoc馈入bash的stdin。请注意,它是在的上下文中运行的/bin/sh
,因此它是posix heredoc,而不是红宝石。通常,这要求将结束标记放在第1列中,由于缩进,此处不是这种情况。
但是,由于它被包裹在红宝石heredoc中,因此strip_heredoc
在此处应用的方法会使其缩痕,将内部heredoc的整个左侧放置在第1列中,然后再进行/bin/sh
查看。
/bin/sh
通常也会在heredoc中扩展变量,这可能会干扰脚本。起始标记“ BASH”周围的单引号指示/bin/sh
在传递给bash之前,请勿在heredoc中进行任何扩展。
但是/bin/sh
,在将字符串传递给bash之前,仍会对字符串应用转义。这意味着反斜杠转义必须加倍以使其/bin/sh
达到bash,即\
成为\\
。
bash选项-xeuo pipefail
是可选的。
这些-euo pipefail
参数告诉bash在严格模式下运行,一旦出现任何失败或对未定义变量的引用,甚至是管道中的命令,它都会停止执行。这将向rake返回错误,这将停止rake任务。通常这就是您想要的。如果要正常的bash行为,可以删除该参数。
-x
bash 的选项和{verbose: false}
参数可以#sh
协同工作,以便rake仅打印实际执行的bash命令。如果您的bash脚本不是要完全运行,例如,如果它具有允许其在脚本中提前退出的测试,则这很有用。
如果您不希望rake任务失败,请注意不要设置非0的退出代码。通常,这意味着您|| exit
无需显式设置退出代码即不想使用任何构造|| exit 0
。
如果您在此过程中遇到任何怪异的怪事,请关闭-o pipefail
。我已经看到一些与之相关的错误,特别是在管道传输到时grep
。