2013-09-01 3 views
6

Код ниже не выводит вывод tail -f. Зачем? Как я могу заставить его работать?back-tick in ruby ​​не работает с командой tail -f

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

Является '«имя файла»' буквальное имя файла (или фиктивной имя, используемое только для вашего вопроса)? Или это имя переменной, которая содержит строку? – sawa

+1

'filename' является манекеном для вопроса – Bhuvan

ответ

7

С помощью опции последующей -f на tail выполненную команду не будет немедленно прекратить.

-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') 

В чем разница здесь? Вместо того, чтобы возвращать outpout команды, он вернет true (команда запускается успешно), false (неудачно) или nil (выполнение команды не выполнено). В связи с тем, что вывод команды не перенаправлен на оператор return, работающий tail -f, он будет печатать контент на стандартный вывод.

Если вы в порядке с получением результатов на стандартный вывод, вы можете просто поместить его в блок Thread. Таким образом, растущий контент 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

Ваш пост - путаный беспорядок и описывает, что происходит вместо того, чтобы объяснять, почему это происходит. Оп уже знает, что происходит. Downvoted. Люди, которые поддержали ваш пост, должны объяснить, почему они его поддержали. Ваши рассуждения выглядят примерно так: если вы выполняете команду, которая не возвращает значение, она не может записываться в stdout; но если вы используете метод system() ruby ​​для выполнения команды, которая не возвращает значение, она будет записывать в stdout. А? – 7stud

+0

Я не утверждал, что если вы выполняете команду, которая не возвращает значение, которое она не может записать в stdout. Также я не вижу на вопрос, что ОП уже знает и чего он не знает. Спасибо за комментарий, однако, я попытаюсь улучшить формулировки. –

+0

platzhirsch wrote: _По окончании прекращения не будет возвращено никакого значения, и поэтому ничего не печатается. Что это значит? Или, говоря иначе, это возвращаемое значение команды или ее отсутствие, связанное с тем, может ли команда писать в stdout? – 7stud

0

Причина, по которой она не работает, заключается в том, что обратные шаги делают отдельный вызов System для запуска команд в обратных тактах. Если вы делаете ps aux | grep tail, вы сможете увидеть, что процесс хвоста фактически запущен.

Код не отображает никаких выходных данных, так как его ожидание завершения хвоста и переход к следующим операторам - его не висят, потому что он отображает вывод команды хвоста.

Даже при нормальной работе вы должны сделать ctrl+C, чтобы закрыть выход команды tail -f. -f используется для вывода добавленных данных по мере роста файла, и, следовательно, tail -f продолжает работать. Попробуйте сделать kill -9 <pid_of_tail>, используя pid из ps aux | grep tail. Затем оставшаяся часть вашего рубинового кода начнет выводить результат.

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` 

... виснет и не выводит ничего, можно сделать вывод, что метод должен быть обратные кавычки пытается захватить весь вывод команды. Другими словами, метод обратных шагов не читается по строке из стандартного вывода команды, т. Е. ориентированный на линию вход. Вместо этого метод backticks считывает входной файл, ориентированный на ориентацию, то есть файл за раз. И поскольку команда tail -f some_file никогда не заканчивает запись на стандартный вывод, метод backticks никогда не читает конец файла, и он зависает, пока он ждет eof.

3) Однако считывание вывода команды файла - это не единственный способ прочитать вывод команды. Вы также можете прочитать вывод команды по строке, используя popen():

my_prog.гь:

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

Смежные вопросы