код выхода проверки системной команды ruby

106

У меня есть несколько системных вызовов в Ruby, таких как следующие, и я хочу одновременно проверять их коды выхода, чтобы мой сценарий завершился, если эта команда не удалась.

system("VBoxManage createvm --name test1")
system("ruby test.rb")

Я хочу что-то вроде

system("VBoxManage createvm --name test1", 0) <- где второй параметр проверяет код выхода и подтверждает, что этот системный вызов был успешным, а если нет, он вызовет ошибку или сделает что-то в этом роде.

Это вообще возможно?

Я пробовал что-то в этом роде, и это тоже не сработало.

system("ruby test.rb")
system("echo $?")

или

`ruby test.rb`
exit_code = `echo $?`
if exit_code != 0
  raise 'Exit code is not zero'
end
user1530318
источник
2
возможный дубликат
ловушки
В приведенном выше примере exit_codeбудет строка - либо, "0\n"либо "1\n", поэтому exit_code != 0всегда будет истинным
dgmstuart

Ответы:

166

Из документации :

система возвращает, trueесли команда дает нулевой статус выхода, falseдля ненулевого статуса выхода. Возвращает, nilесли выполнение команды не удалось.

system("unknown command")     #=> nil
system("echo foo")            #=> true
system("echo foo | grep bar") #=> false

более того

Статус ошибки доступен в $?.

system("VBoxManage createvm --invalid-option")

$?             #=> #<Process::Status: pid 9926 exit 2>
$?.exitstatus  #=> 2
Стефан
источник
2
и как записать его вывод (не код выхода) в переменную?
ア レ ッ ク ス
Если вы работаете с консолью rails, проверяя это, просто имейте в виду, что вы можете потерять значение $? поэтому вам нужно захватить его как часть вашей команды REPL [10] pry(main)> system("touch /root/test 2> /dev/null") => false [11] pry(main)> $?.exitstatus => 0 [12] pry(main)> system("touch /root/test 2> /dev/null"); $?.exitstatus => 1
lardcanoe 09
Еще одно отличное сравнение systemобратных кавычек %xи приведено execздесь: stackoverflow.com/questions/6338908/…
Том Харрисон,
38

Для меня я предпочел использовать `` для вызова команд оболочки и проверки $? чтобы получить статус процесса. $? является объектом статуса процесса, вы можете получить информацию о процессе команды из этого объекта, в том числе: код статуса, статус выполнения, pid и т. д.

Некоторые полезные методы $? объект:

   $?.exitstatus => return error code    
   $?.success? => return true if error code is 0, otherwise false
   $?.pid => created process pid
Houcheng
источник
1
С помощью Rubocop, я узнал, что машиночитаемый псевдоним $?является$CHILD_STATUS
RajaRaviVarma
26

systemвозвращается, falseесли команда имеет ненулевой код выхода или nilее нет.

Следовательно

system( "foo" ) or exit

или

system( "foo" ) or raise "Something went wrong with foo"

должны работать и достаточно лаконичны.

Нил Слейтер
источник
6

Вы не фиксируете результат своего systemвызова, в котором возвращается код результата:

exit_code = system("ruby test.rb")

Помните, что каждый systemвызов или эквивалент, который включает в себя метод обратной кавычки, порождает новую оболочку, поэтому невозможно захватить результат среды предыдущей оболочки. В этом случае exit_codeесть , trueесли все получилось, в nilпротивном случае.

Команда popen3обеспечивает более низкоуровневую детализацию.

тадман
источник
2
Open3.capture3- особенно простой метод для такого рода задач.
Железный Человек
6

Один из способов сделать это - связать их, используя andили &&:

system("VBoxManage createvm --name test1") and system("ruby test.rb")

Второй вызов не будет выполнен, если первый не сработает.

Вы можете обернуть их в, if ()чтобы дать вам некоторый контроль над потоком:

if (
  system("VBoxManage createvm --name test1") && 
  system("ruby test.rb")
) 
  # do something
else
  # do something with $?
end
Железный Человек
источник
Пока это то, чего я хочу достичь, достаточно просто и ясно. Спасибо
mochadwi