сброс пользователя в IRB после чтения из канала

У меня есть этот скрипт, который при выполнении переводит пользователя в сеанс IRB.

Все хорошо, но когда я использую каналы *nix для получения ввода (например, с cat), сеанс IRB немедленно завершается.

Я мог бы сократить сценарий (назовем его myscript.rb) до следующего:

require 'irb'

if $stdin.stat.size > 0
  @text = $stdin.read 
else
  @text= "nothing"
end

ARGV.clear
IRB.start

При выполнении типа: ruby myscript.rb я оказываюсь в сеансе IRB (как и ожидалось).

Но (при условии, что foo.txt существует в cwd): cat foo.txt | ruby myscript.rb просто напечатает приглашение IRB, а затем сеанс IRB будет закрыт (меня перебрасывают в $bash).

Любые известные обходные пути или идеи?

Кстати: на ruby ​​​​1.8.7 он ведет себя одинаково, как и на 1.9.2.


person aurelian    schedule 03.01.2011    source источник


Ответы (3)


Я думаю, ваша проблема в том, что когда вы подключаетесь к своему сценарию, STDIN будет потоком из вашего файла, поэтому, когда вы запускаете IRB, он будет читать из того же потока, но обратите внимание, что он находится в конце, и выйдете, как и было бы. когда вы набираете ctrl-D (что является ручным сигналом конца файла).

Вы можете снова открыть STDIN для чтения с tty (т.е. с клавиатуры) следующим образом:

STDIN.reopen(File.open('/dev/tty', 'r'))

но для меня это выглядит немного странно, я не получаю надлежащего запроса IRB. Хотя ИРБ работает.

person Theo    schedule 03.01.2011
comment
похоже, что это проблема, и повторное открытие $stdin создаст (я думаю) IRB по умолчанию (без приглашения, .irbrc не прочитан и т. д.). - person aurelian; 03.01.2011
comment
с другой стороны, перемотка назад или поиск (0) на $stdin не будет работать (это tty). - person aurelian; 03.01.2011
comment
Что вы имеете в виду, говоря, что seek(0) не работает, зачем вам это нужно? Если я не понял, я имел в виду, что вы снова открываете стандартный ввод непосредственно перед IRB.start. - person Theo; 03.01.2011
comment
вместо повторного открытия я пытался выполнить $stdin.rewind (или .seek). Вы были очень ясны, спасибо за ответ. - person aurelian; 03.01.2011
comment
+1 Мне всегда было интересно, как читать со стандартного ввода после одного или нескольких EOF. Вероятно, вам нужна блочная форма File.open, чтобы избежать утечки файловых дескрипторов. - person Kelvin; 29.02.2012

@Theo определил проблему.

Кроме того, требование irb перед IRB.start исправит отсутствующие настройки IRB. В итоге код выглядит так:

if $stdin.stat.size > 0
  @text = $stdin.read
  $stdin.reopen(File.open("/dev/tty", "r"))
else
  @text= "nothing"
end

require 'irb'
ARGV.clear
IRB.start
person aurelian    schedule 03.01.2011

$stdin.read читает ваш ввод до того, как IRB сможет его прочитать (если вы пытаетесь заставить IRB выполнять команды со стандартного ввода).

person viktors    schedule 03.01.2011
comment
foo.txt — это обычный текстовый файл. - person aurelian; 03.01.2011