Ruby kod wyjścia sprawdzania systemu polecenia

106

Mam kilka wywołań systemowych w Rubim, takich jak poniższe, i chcę jednocześnie sprawdzić ich kody zakończenia, aby mój skrypt zakończył działanie, jeśli to polecenie zawiedzie.

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

Chcę czegoś takiego

system("VBoxManage createvm --name test1", 0) <- gdzie drugi parametr sprawdza kod zakończenia i potwierdza, że ​​wywołanie systemowe się powiodło, a jeśli nie, spowoduje zgłoszenie błędu lub zrobi coś podobnego.

Czy to w ogóle możliwe?

Próbowałem czegoś podobnego do tego i to też nie zadziałało.

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

lub

`ruby test.rb`
exit_code = `echo $?`
if exit_code != 0
  raise 'Exit code is not zero'
end
user1530318
źródło
2
możliwy duplikat
wyłapywania
W powyższym przykładzie exit_codebędzie ciągiem - albo "0\n"albo "1\n", więc exit_code != 0zawsze będzie prawdziwe
dgmstuart

Odpowiedzi:

166

Z dokumentacji :

system zwraca, truejeśli polecenie daje zerowy kod wyjścia, falsedla niezerowego kodu wyjścia. Zwraca, niljeśli wykonanie polecenia nie powiedzie się.

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

Ponadto

Status błędu jest dostępny w $?.

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

$?             #=> #<Process::Status: pid 9926 exit 2>
$?.exitstatus  #=> 2
Stefan
źródło
2
i jak przechwycić jego wynik (nie kod wyjścia) do zmiennej?
ア レ ッ ク ス
Jeśli jesteś w konsoli railsowej i testujesz to, pamiętaj, że możesz stracić wartość $? więc musisz go uchwycić jako część polecenia 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
Kolejne doskonałe porównanie systemodwrotnych apostrofów %xi execpodane tutaj: stackoverflow.com/questions/6338908/ ...
Tom Harrison
38

Dla mnie wolałem używać ``, aby wywołać polecenia powłoki i sprawdzić $? aby uzyskać status procesu. $? jest obiektem statusu procesu, możesz pobrać informacje o procesie polecenia z tego obiektu, w tym: kod statusu, status wykonania, pid itp.

Niektóre przydatne metody $? obiekt:

   $?.exitstatus => return error code    
   $?.success? => return true if error code is 0, otherwise false
   $?.pid => created process pid
Houcheng
źródło
1
Z pomocą Rubocopa dowiedziałem się, że czytelny alias dla $?to$CHILD_STATUS
RajaRaviVarma
26

systemzwraca, falsejeśli polecenie ma niezerowy kod zakończenia lub niljeśli nie ma polecenia.

W związku z tym

system( "foo" ) or exit

lub

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

powinny działać i są dość zwięzłe.

Neil Slater
źródło
6

Nie przechwytujesz wyniku systempołączenia, czyli miejsca, w którym zwracany jest kod wyniku:

exit_code = system("ruby test.rb")

Pamiętaj, że każde systemwywołanie lub odpowiednik, który zawiera metodę backtick, powoduje powstanie nowej powłoki, więc nie jest możliwe przechwycenie wyniku środowiska poprzedniej powłoki. W tym przypadku exit_codejest, truejeśli wszystko się udało, w nilprzeciwnym razie.

popen3Poleceń dostarcza więcej szczegółów na niskim poziomie.

tadman
źródło
2
Open3.capture3to szczególnie łatwa metoda do tego rodzaju zadań.
Tin Man,
6

Jednym ze sposobów jest połączenie ich w łańcuch za pomocą andlub &&:

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

Drugie wywołanie nie zostanie uruchomione, jeśli pierwsze się nie powiedzie.

Możesz opakować je w an, if ()aby uzyskać pewną kontrolę przepływu:

if (
  system("VBoxManage createvm --name test1") && 
  system("ruby test.rb")
) 
  # do something
else
  # do something with $?
end
Blaszany Człowiek
źródło
To jest to, co chcę osiągnąć, dość proste i jasne. Dziękuję
mochadwi