2013-09-01 66 views
6

下面的代碼不打印tail -f的輸出。爲什麼?我怎樣才能使它工作?ruby​​中的back-tick不適用於tail -f命令

#myApp.rb 
`ls`    #works fine 
`tail -f filename`  #does not work. why? 
+0

是' 「文件名」'文件(或只用於你的問題一個虛擬的名字)的字面名字?或者它是一個包含字符串的變量的名稱? – sawa

+1

'filename'是一個虛擬的問題 – Bhuvan

回答

7

通過使用如下選項-ftail執行的命令不會立即終止。

-f, --follow[={name|descriptor}] 
    output appended data as the file grows; 

使用反引號的想法(或%x快捷方式),而不是使用system('...')是,這些語句返回執行的命令的輸出。這樣,您就可以把結果保存在一個變量:

dir_content = `ls` 

tail -f產生另一個過程,這個過程不斷寫到標準輸出而不終止。因此,你的陳述從未完成。沒有完成聲明,就不能返回一個值。如果您想觀看並輸出不斷增長的文件,請參閱以下問題的解決方案:

Watch/read a growing log file

或者,你可以像這樣通過system運行命令:

system('tail -f filename') 

是這裏有什麼區別?它不會返回命令的輸出,而會返回true(命令運行成功),false(失敗)或nil(命令執行失敗)。由於這個事實,命令的輸出沒有被重定向到運行tail -f的return語句,它將把內容打印到標準輸出。

如果您可以將結果轉換爲標準輸出,那麼您可以簡單地將它放入一個線程塊。這樣,不斷增加的filename內容被寫入標準輸出,您可以繼續執行其他Ruby代碼。

Thread.new { system('tail -f filename') } 

如果你想擁有完全的控制,捕獲輸出,以便將其存儲檢索在腳本的另一點,然後看看回答以下問題描述這樣一種方法:

Continuously read from STDOUT of external process in Ruby

它基於創建和管理僞終端的PTY模塊。基本上你可以通過這個模塊產生另一個終端。代碼可能看起來像這樣:

require 'pty' 
cmd = "tail -f filename" 
begin 
    PTY.spawn(cmd) do |stdin, stdout, pid| 
    begin 
     # Do something with the output here: just printing to demonstrate it 
     stdin.each { |line| print line } 
    rescue Errno::EIO 
     puts "Errno:EIO error, but this probably just means " + 
      "that the process has finished giving output" 
    end 
    end 
rescue PTY::ChildExited 
    puts "The child process exited!" 
end 

最後,還有一個套接字方法。在Bash中打開一個套接字或使用socat,將tail -f的輸出傳遞給套接字並從套接字讀入Ruby。

+0

您的文章是一個混亂的混亂,並描述了發生了什麼,而不是解釋爲什麼會發生。該op已經知道發生了什麼。 Downvoted。那些贊成你的帖子的人應該解釋他們爲什麼投了贊成票。你的推理是這樣的:如果你執行一個不返回值的命令,它不能寫入標準輸出;但是如果你使用ruby的system()方法來執行一個不返回值的命令,它將寫入stdout。咦? – 7stud

+0

我還沒有說過,如果你執行一個不返回值的命令,它就不能寫入標準輸出。另外我從問題中沒有看到OP已經知道什麼以及他不知道什麼。感謝評論,但我會嘗試改進配方。 –

+0

platzhirsch寫道:_沒有終止沒有返回值將被給予,所以什麼都不印._那是什麼意思呢?換句話說,命令的返回值還是與命令是否可以寫入標準輸出有關? – 7stud

0

它不起作用的原因是反引號分別調用System來在反引號內運行命令。 如果你做了ps aux | grep tail,你將能夠看到尾部進程實際上正在運行。

代碼沒有顯示任何輸出,因爲它等待尾部終止並繼續下一個語句 - 它沒有掛起,因爲它顯示尾部命令的輸出。

即使在正常操作中,您也必須執行ctrl+C來關閉tail -f命令的輸出。 -f用於在文件增長時輸出附加數據,因此tail -f將繼續運行。 嘗試使用ps aux | grep tail的pid做kill -9 <pid_of_tail>。然後你的ruby代碼的其餘部分將開始輸出結果。

ls,tail without -f調用工作,因爲他們自己終止。

如果你有興趣做紅寶石尾巴,你可以看看這個file-tail寶石http://flori.github.io/file-tail/doc/index.html

1

1)根據反引號文檔,

`cmd` 
Returns the standard output of running cmd in a subshell. 

所以,如果你寫:

puts `some command` 

然後紅寶石應該打印任何一些命令輸出。

2)根據尾巴做人頁:

The tail utility displays the contents of file...to the standard 
output. 

但命令:

puts `tail -f some_file` 

儘管沒有打印任何運行:

$ tail -f some_file 

發送輸出到標準輸出。尾巴手冊頁也說

The -f option causes tail to not stop when 
end of file is reached, but rather to wait 
for additional data to be appended to the 
[the file]. 

這是什麼意思?它與手頭的問題有什麼關係?

由於運行程序:

puts `tail -f some_file` 

...掛起,不輸出什麼,你可以推斷,反引號方法必須試圖捕捉命令的整個輸出。換句話說,反推方法不會從命令的標準輸出逐行讀取,即面向行的輸入。相反,反引號方法一次讀取面向文件的輸入,即一個文件。而且因爲命令tail -f some_file從未完成寫入標準輸出,所以反引號方法永遠不會讀取文件結尾,並且在等待eof時掛起。

3)然而,讀取命令的輸出時間的文件不是讀取命令輸出的唯一方法。您也可以使用popen()一次讀取命令的輸出行:

my_prog。RB:

IO.popen('tail -f data.txt') do |pipe| 
    while line = pipe.gets do #gets() reads up to the next newline, then returns 
    puts line 
    end 
end 


--output(terminal window 1):-- 
$ ruby my_prog.rb 
A 
B 
C 
<hangs> 

--output(terminal window 2):-- 
echo 'D' >> data.txt 

--output(terminal window 1):-- 
A 
B 
C 
D 
<hangs> 

回聲手冊頁:

The echo utility writes any specified operands...followed 
by a newline (`\n') character. 
+0

像一個魅力工作感謝:) – Faizan