从Rakefile执行bash命令

我想从Rakefile执行一些bash命令。 我的主动shell是bash ,我将从bash调用rake

我在我的Rakefile包含了以下内容

 task :hello do %{echo "World!"} end 

但执行rake hello没有输出?

如何从Rakefile执行bash命令?

:这不是重复的,因为它具体询问如何从Rakefile执行bash命令。

我认为耙子想要发生的方式是: http : //rubydoc.info/gems/rake/FileUtils#sh-instance_method例如:

 task :test do sh "ls" end 

内置rake函数sh处理命令的返回值(如果命令的返回值不是0,则任务失败),并且还输出命令输出。

有几种方法可以在ruby中执行shell命令。 一个简单的(也许是最常见的)是使用反引号:

 task :hello do `echo "World!"` end 

在shell命令的标准输出成为返回值的情况下,反引号具有很好的效果。 所以,例如,你可以通过ls的输出

 shell_dir_listing = `ls` 

但是还有很多其他的方法可以调用shell命令,它们都有好处/缺点,工作方式也不同。 这篇文章详细解释了select,但是这里有一个简单的总结可能性:

  • stdout =%x {cmd} – 反引号的替代语法,在幕后它做同样的事情

  • exec(cmd) – 用新的cmd进程完全replace正在运行的进程

  • 成功=系统(CMD) – 运行一个subprocess,并成功/失败返回true / false(基于cmd退出状态)

  • IO#popen(cmd){| io | } – 运行一个subprocess,将stdout和stderr连接到io

  • stdin,stdout,stderr = Open3.popen3(cmd) – 运行一个subprocess并连接到所有pipe道(in,out,err)

%{echo "World!"}定义了一个String。 我希望你想要%x{echo "World!"}

%x{echo "World!"}执行命令并返回输出(stdout)。 你不会看到结果。 但是你可以这样做:

 puts %x{echo "World!"} 

有更多的方法来调用系统命令:

  • 反衬:`
  • system( cmd )
  • popen
  • Open3#popen3

鉴于共识似乎更喜欢rake的#sh方法,但OP明确地要求bash,这个答案可能有一些用处。

这是相关的,因为Rake#sh使用Kernel#system调用来运行shell命令。 Ruby将其硬编码到/bin/sh ,忽略用户在环境中configuration的shell或$SHELL

这是一个从/bin/sh调用bash的解决方法,允许你仍然使用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 

#strip_heredoc从轨道借用:

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的标准input。 请注意,它运行在/bin/sh的上下文中,所以这是一个posix heredoc不是一个ruby。 通常情况下,需要将结束标记放在第1列中,这是因为缩进而不是这种情况。

然而,因为它被包装在ruby heredoc中,所以在strip_heredoc应用的strip_heredoc方法取消了它,在/bin/sh之前将内部heredoc的左侧整体放在第一列中。

/bin/sh通常也会在heredoc中扩展variables,这可能会干扰脚本。 围绕开始标记“BASH”的单引号告诉/bin/sh在传递给bash之前,不要在heredoc内部展开任何内容。

然而/bin/sh在把它传递给bash之前仍然对string应用转义。 这意味着反斜杠转义必须加倍,以通过/bin/sh bash,即\成为\\

bash选项-xeuo pipefail是可选的。

-euo pipefail参数告诉bash在严格模式下运行,当任何失败或引用一个未定义的variables,甚至是pipe道中的命令时,都会停止执行。 这将返回一个错误耙,这将停止耙任务。 通常这是你想要的。 如果你想要正常的bash行为,参数可以被删除。

#sh-x选项和{verbose: false}参数#sh工作,所以rake只打印实际执行的bash命令。 如果您的bash脚本不是完全运行的,例如它有一个允许它在脚本中早期退出的testing,这是非常有用的。

如果您不希望rake任务失败,请小心不要设置0以外的退出代码。 通常这意味着你不想使用任何|| exit || exit构造没有显式设置退出代码,即|| exit 0 || exit 0

如果你遇到任何bash怪异的情况,关掉-o pipefail 。 我已经看到了与stream水线grep有关的一些bugginess。

Interesting Posts