簡體   English   中英

從 Rakefile 執行 bash 命令

[英]Execute bash commands from a Rakefile

我想從Rakefile執行一些bash命令。

我在我的Rakefile嘗試了以下Rakefile

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

但是在執行rake hello時沒有輸出? 如何從 Rakefile 執行 bash 命令?

注意:這不是重復的,因為它專門詢問如何從Rakefile執行 bash 命令。

我認為 rake 希望這種情況發生的方式是: 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 命令,它們都有優點/缺點並且工作方式不同。 本文詳細解釋了這些選擇,但這里有一個快速總結的可能性:

鑒於共識似乎更喜歡 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應用的strip_heredoc方法取消了它的縮進,在/bin/sh看到它之前將內部 heredoc 的整個左側放置在第 1 列中。

/bin/sh通常也會擴展 heredoc 中的變量,這可能會干擾腳本。 開始標記 'BASH' 周圍的單引號告訴/bin/sh在將其傳遞給 bash 之前不要在heredoc 內展開任何內容。

但是/bin/sh在將字符串傳遞給 bash 之前仍然對字符串應用轉義。 這意味着反斜杠轉義必須加倍才能通過/bin/sh到 bash,即\\變為\\\\

bash 選項-xeu是可選的。

-eu參數告訴 bash 以嚴格模式運行,這會在任何失敗或引用未定義變量時停止執行。 這將向 rake 返回一個錯誤,這將停止 rake 任務。 通常,這就是您想要的。 如果您想要正常的 bash 行為,可以刪除這些參數。

bash 的-x選項和#sh {verbose: false}參數#sh工作,因此 rake 只打印實際執行的 bash 命令。 如果您的 bash 腳本不打算完整運行,這將很有用,例如,如果它有一個允許它在腳本早期正常退出的測試。

如果您不希望 rake 任務失敗,請注意不要設置 0 以外的退出代碼。 通常,這意味着您不想使用任何|| exit 沒有明確設置退出代碼的|| exit構造,即|| exit 0 || exit 0

%{echo "World!"}定義了一個字符串。 我希望你想要%x{echo "World!"}

%x{echo "World!"}執行命令並返回輸出 (stdout)。 你不會看到結果。 但你可以這樣做:

puts %x{echo "World!"}

還有更多調用系統命令的方法:

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

有兩種方式:

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 但標准輸出不會顯示在屏幕上。 因此,當您需要命令結果時,最好使用%x( expr )

但是如果你只想做一個shell命令,我建議你使用sh "expr" 因為sh "irb"會讓你進入 irb shell,而%x(irb)會死。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM