【问题标题】:Execute bash commands from a Rakefile从 Rakefile 执行 bash 命令
【发布时间】:2012-04-05 11:09:11
【问题描述】:

我想从Rakefile 执行一些bash 命令。

我在Rakefile 中尝试了以下方法

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

但是在执行rake hello 时没有输出? 如何从 Rakefile 执行 bash 命令?

注意:这不是重复的,因为它专门询问如何从 Rakefile 执行 bash 命令。

【问题讨论】:

  • 不是%{,而是%x(,它将stdout作为字符串返回而不是打印出来。
  • 它不是如上所述的重复,因为它专门要求在 rake 文件中执行,而不是在常规 ruby​​ 程序中执行。
  • 当它专门询问 Rake 而不是一般的 Ruby 时,为什么会被标记为重复?!

标签: ruby bash rake


【解决方案1】:

我认为 rake 希望这种情况发生的方式是:http://rubydoc.info/gems/rake/FileUtils#sh-instance_method 示例:

task :test do
  sh "ls"
end

内置的 rake 函数 sh 负责命令的返回值(如果命令的返回值不是 0,则任务失败),此外它还输出命令输出。

【讨论】:

  • 其他解决方案,如使用反引号等执行不是 rake 方法,而是 ruby​​ 方法(请参阅zhangxh.net/programming/ruby/… 了解 6 种不同的方法)。 rake 在“sh”函数中所做的是自动处理命令的返回值,以便如果 sh 中的一个命令失败,则 rake 任务失败。大多数情况下,这正是您想要的。从 ruby​​ 执行命令的其他方法不应该经常在 rake 中使用。
  • sh 相对于系统的另一个好处:默认情况下,sh 似乎更详细地回显命令。
  • 我在 rake 文件而不是系统中使用 sh 取得了最大的成功。
  • 该链接已于 2014 年 7 月失效,因为 RubyForge 已不复存在。
  • @ArtoBendiken 更新了评论以包含指向 rdoc 的最新链接。
【解决方案2】:

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

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

在 shell 命令的标准输出变成返回值时,反引号有一个很好的效果。所以,例如,你可以通过做得到ls的输出

shell_dir_listing = `ls`

但是还有许多其他调用 shell 命令的方法,它们都有优点/缺点并且工作方式不同。 This article 详细解释了这些选择,但这里有一个快速总结的可能性:

【讨论】:

  • 这确实将输出记录到控制台,这可能有点令人困惑。在 rake 中,您可以使用 sh "some_task" 将命令打印到终端,就像您直接从终端运行一样。
【解决方案3】:

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

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

这是一个从 /bin/sh 调用 bash 的解决方法,允许您仍然使用 sh 方法:

task :hello_world do
  sh <<-EOS.strip_heredoc, {verbose: false}
    /bin/bash -xeu <<'BASH'
    echo "Hello, world!"
    BASH
  EOS
end

class String
  def strip_heredoc
    gsub(/^#{scan(/^[ \t]*(?=\S)/).min}/, ''.freeze)
  end
end

#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 的标准输入。请注意,它是在/bin/sh 的上下文中运行的,所以它是一个posix heredoc,而不是一个ruby。通常这要求结束标记位于第 1 列中,但由于缩进,此处不是这种情况。

但是,因为它被包裹在一个 ruby​​ heredoc 中,所以在此处应用的 strip_heredoc 方法会对其进行去缩进,将内部 heredoc 的整个左侧放在第 1 列中,然后 /bin/sh 看到它。

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

不过,/bin/sh 在将字符串传递给 bash 之前,仍然会对字符串应用转义。这意味着反斜杠转义必须加倍才能通过/bin/sh 到bash,即\ 变为\\

bash 选项-xeu 是可选的。

-eu 参数告诉 bash 在严格模式下运行,这会在任何失败或对未定义变量的引用时停止执行。这将向 rake 返回一个错误,这将停止 rake 任务。通常,这就是您想要的。如果您想要正常的 bash 行为,可以删除参数。

bash 的-x 选项和#sh{verbose: false} 参数协同工作,因此 rake 只打印实际执行的 bash 命令。如果您的 bash 脚本不打算完整运行,这很有用,例如,如果它有一个测试允许它在脚本早期正常退出。

如果您不希望 rake 任务失败,请注意不要设置 0 以外的退出代码。通常,这意味着您不想在不明确设置退出代码的情况下使用任何 || exit 构造,即 || exit 0

【讨论】:

  • 谢谢。这有助于我朝着正确的方向前进。我在一个 ruby​​ 脚本中使用它,我需要调用一些需要 bash 的方法。我还使用带有一些“奇怪”字符的长字符串。这是我的做法,也许它可以帮助某人。 system(%[xx=$(cat &lt;&lt;EOT\n#{body_text}\nEOT\n); bash &lt;&lt;BASH\n. #{ENV['HOME']}/.bash_profile; echo "$xx" | own_mail -TRm\nBASH\n)]。然而,最简单的方法是将所有内容放在一个 bash 脚本中,然后调用它system("path/my_bash_script.sh")
【解决方案4】:

%{echo "World!"} 定义一个字符串。我猜你想要%x{echo "World!"}

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

puts %x{echo "World!"}

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

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

【讨论】:

  • 需要注意的是,%x 和反引号实际上是调用等效的 ruby​​ 内核方法,它们是相同方法的替代语法。
  • system( cmd ) 为我工作。我正在尝试使用 wkhtmltopdf 编写一个 pdf 生成器脚本。
【解决方案5】:

有两种方式:

sh " expr "

%x( expr )

注意 ( expr ) 可以是 { expr } , |表达式 |或`expr`

不同的是,sh "expr" 是一个 ruby​​ 方法来执行某些东西,而 %x( expr ) 是 ruby​​ 内置方法。结果和行动不同。这是一个例子

task :default do
value = sh "echo hello"
puts value
value = %x(echo world)
puts value
end

得到:

hello  # from sh "echo hello"
true   # from puts value
world  # from puts value

您可以看到%x( expr ) 只会执行shell expr,但stdout 不会显示在屏幕上。所以,需要命令结果的时候最好使用%x( expr )

但是如果你只是想做一个shell命令,我建议你使用sh "expr"。因为sh "irb"会让你进入irb shell,而%x(irb)会死。

【讨论】:

    猜你喜欢
    • 2023-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-26
    • 1970-01-01
    • 2014-01-11
    • 2019-06-22
    相关资源
    最近更新 更多