Ruby中執行Linux shell命令的六種方法詳解_ruby專題

來源:互聯網
上載者:User

在Ruby中,執行shell命令是一件不奇怪的事情,Ruby提供了大概6種方法供開發人員進行實現。這些方法都很簡單,本文將具體介紹一下如何在Ruby指令碼中進行調用終端命令。

exec

exec會將指定的命令替換掉當前進程中的操作,指定命令結束後,進程結束。

複製代碼 代碼如下:

exec 'echo "hello world"'
print 'abc'

執行上述的命令,結果如下,我們可以看到沒有abc的輸出,可以看出來,在執行echo "hello world"命令後進程就結束了。不會繼續執行後面的print 'abc'。

複製代碼 代碼如下:

ruby testCommand.rb
hello world

使用exec一個頭疼的事情就是沒有辦法知道shell命令執行成功還是失敗。

system

system和exec相似,但是system執行的命令不會是在當前進程,而是在一個新建立的進程。system會返回布爾值來表明命令執行結果是成功還是失敗。

複製代碼 代碼如下:

$ irb
> system 'echo "hello $HOSTNAME"'
hello androidyue
 => true
> puts $?
pid 11845 exit 0
 => nil
> system 'false'
 => false
> puts $?
pid 11858 exit 1
 => nil
>>

system會將進程的退出的狀態代碼賦值給$?,如果程式正常退出,$?的值為0,否則為非0。通過檢測退出的狀態代碼我們可以在ruby指令碼中拋出異常或者進行重試操作。

註:在Unix-like系統中進程的退出狀態代碼以0和非0表示,0代表成功,非0代表失敗。

system可以告訴我們命令執行是成功還是失敗,但是有些時候我們需要得到執行命令的輸出,並在指令碼中使用。顯然system無法直接滿足,需要我們使用反引號來實現。

反引號(`)

使用反引號是shell中常用的擷取命令輸出內容的方法,在ruby中也是可以,而且一點都需要做改變。使用反引號執行命令也會將命令在另一個進程中執行。

複製代碼 代碼如下:

1.9.3p448 :013 > today = `date`
 => "Sat Nov 15 19:28:55 CST 2014\n"
1.9.3p448 :014 > $?
 => #<Process::Status: pid 11925 exit 0>
1.9.3p448 :015 > $?.to_i
 => 0
1.9.3p448 :016 >

上面的方法如此簡單,我們可以直接對返回的字串結果進行操作。

注意,$?已經不再是上述的那樣單純的退出狀態代碼了,它實際上是一個Process::Status對象。我們從中不僅可以知道進程的退出狀態代碼也可以知道進程的ID。使用$?.to_i會得到退出的狀態代碼,使用$?.to_s會得到包含了進程id,退出狀態代碼等資訊的字串。

使用反引號的一個結果就是我們只能得到標準的輸出(stdout)而不能得到標準的錯誤資訊(stderr),比如下面的例子,我們執行一個輸出錯誤字串的perl指令碼。

複製代碼 代碼如下:

 $ irb
  >> warning = `perl -e "warn 'dust in the wind'"`
  dust in the wind at -e line 1.
  => ""
  >> puts warning

  => nil

可以看出,warning並沒有得到出錯的資訊,這就表明反引號無法得到標準錯誤的資訊。

IO#popen

IO#popen也是一種執行命令的方法,其命令也是在另外的進程中執行。使用popen你可以像操作IO對象一樣處理標準輸入和輸出。

複製代碼 代碼如下:

$ irb
>> IO.popen("date") { |f| puts f.gets }
Mon Mar 12 18:58:56 PDT 2007
=> nil

Open3#popen3

在標準的Ruby庫中還提供了一個Open3。使用這個類我們可以很容易的對標準輸入,輸出,錯誤進行處理。這裡我們使用一個可以互動的工具dc。dc是一種逆波蘭運算式(又叫做尾碼運算式,每一運算子都置於其運算對象之後)的計算機,支援從標準輸入讀取數學運算式。在這個例子中,我們將兩個數值和一個操作符進行壓棧處理。然後使用p來輸出結果。比如我們輸入5和10,然後輸入+,然後會得到15\n的輸出。

複製代碼 代碼如下:

$ irb
  >> stdin, stdout, stderr = Open3.popen3('dc')
  => [#<IO:0x6e5474>, #<IO:0x6e5438>, #<IO:0x6e53d4>]
  >> stdin.puts(5)
  => nil
  >> stdin.puts(10)
  => nil
  >> stdin.puts("+")
  => nil
  >> stdin.puts("p")
  => nil
  >> stdout.gets
  => "15\n"

使用這個方法,我們不僅可以讀取到命令的輸出還可以對命令進行輸入操作。這個方法對於進行互動操作很方便。通過popen3,我們還可以得到標準的錯誤資訊。

複製代碼 代碼如下:

  # (irb continued...)
  >> stdin.puts("asdfasdfasdfasdf")
  => nil
  >> stderr.gets
  => "dc: stack empty\n"

但是,在ruby 1.8.5中popen3有一個缺陷,進程的退出狀態沒有寫入到$?中。

複製代碼 代碼如下:

$ irb
  >> require "open3"
  => true
  >> stdin, stdout, stderr = Open3.popen3('false')
  => [#<IO:0x6f39c0>, #<IO:0x6f3984>, #<IO:0x6f3920>]
  >> $?
  => #<Process::Status: pid=26285,exited(0)>
  >> $?.to_i
  => 0

為什麼是0,false命令執行後的退出狀態應該是非0才對,由於這個缺陷,我們需要瞭解一下Open4

Open4#popen4

Open4#popen4使用起來和Open3#popen3差不多,而且我們也可以得到程式的退出狀態。popen4還可以返回一個子進程ID。你也可以通過Process::waitpid2 加上對應的進程ID獲得進程退出狀態。但是前提是要安裝open4的gem。

複製代碼 代碼如下:

$ irb
  >> require "open4"
  => true
  >> pid, stdin, stdout, stderr = Open4::popen4 "false"
  => [26327, #<IO:0x6dff24>, #<IO:0x6dfee8>, #<IO:0x6dfe84>]
  >> $?
  => nil
  >> pid
  => 26327
  >> ignored, status = Process::waitpid2 pid
  => [26327, #<Process::Status: pid=26327,exited(1)>]
  >> status.to_i
  => 256

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.