Ruby, Różnica między exec, systemem a% x () lub Backticks

370

Jaka jest różnica między następującymi metodami Ruby?

exec, systemI %x()czy backticks

Wiem, że są one używane do programowego wykonywania poleceń terminalowych za pośrednictwem Ruby, ale chciałbym wiedzieć, dlaczego istnieją trzy różne sposoby, aby to zrobić.

Pan Black
źródło
1
Te i wiele innych poleceń zostały dość dobrze wyjaśnione w dokumentacji: backticks systemu exec
zetetic
1
Istnieje świetny artykuł Ruby Quicktips na ten temat: Wykonywanie poleceń powłoki .
Simon Perepelitsa
6
Ponieważ ktoś właśnie wykopał ten stary wątek, „Praca z procesami uniksowymi” jest doskonałą książką dla rubinów zainteresowanych tematem: workingwithunixprocesses.com
Michael Kohl
1
Dziwi mnie, że żadna z odpowiedzi nie wspomina sh.
Dennis,
@Dennis Kiedy zadawałem to pytanie, ruby ​​1.9.3 * nie zostało wydane.
Mr. Black

Odpowiedzi:

411

system

systemMetoda nazywa program systemowy. Musisz podać polecenie jako argument ciągu dla tej metody. Na przykład:

>> system("date")
Wed Sep 4 22:03:44 CEST 2013
=> true

Program wywołany użyje prąd STDIN, STDOUTa STDERRobiekty z programu Ruby. W rzeczywistości faktyczna wartość zwracana to albo true, falsealbo nil. W przykładzie data została wydrukowana przez obiekt IO obiektu STDIN. Metoda zwróci, truejeśli proces zakończy się ze statusem zerowym, falsejeśli proces zakończy się ze statusem niezerowym i niljeśli wykonanie się nie powiedzie.

Innym efektem ubocznym jest to, że zmienna globalna $?jest ustawiona na Process::Statusobiekt. Ten obiekt będzie zawierał informacje o samym wywołaniu, w tym identyfikator procesu (PID) wywoływanego procesu i status wyjścia.

>> system("date")
Wed Sep 4 22:11:02 CEST 2013
=> true
>> $?
=> #<Process::Status: pid 15470 exit 0>

Backticks

Backticks (``) wywołują program systemowy i zwracają jego wynik. W przeciwieństwie do pierwszego podejścia, polecenie nie jest przekazywane przez ciąg znaków, ale przez umieszczenie go w parze backticks.

>> `date`
=> Wed Sep 4 22:22:51 CEST 2013   

Zmienna globalna $?jest również ustawiana za pomocą strzałek wstecznych. Za pomocą backticksa można również użyć interpolacji łańcuchów.

% x ()

Korzystanie %xjest alternatywą dla stylu backticks. Zwróci również wynik. Podobnie jak jego krewni %wi %q(między innymi), dowolny ogranicznik będzie wystarczający, o ile pasują do niego ograniczniki. Oznacza to %x(date), %x{date}i %x-date-wszystkie są synonimami. Podobnie jak backticks %xmogą korzystać z interpolacji łańcuchów.

exec

Przy użyciu Kernel#execbieżącego procesu (skryptu Ruby) zostaje zastąpiony procesem wywoływanym przez exec. Metoda może przyjąć ciąg jako argument. W takim przypadku łańcuch będzie podlegał rozszerzeniu powłoki. W przypadku użycia więcej niż jednego argumentu pierwszy służy do wykonania programu, a następujące argumenty są podawane jako argumenty programu, który ma zostać wywołany.

Open3.popen3

Czasami wymagane informacje są zapisywane na standardowe dane wejściowe lub standardowe błędy i trzeba je również kontrolować. Tutaj Open3.popen3przydaje:

require 'open3'

Open3.popen3("curl http://example.com") do |stdin, stdout, stderr, thread|
   pid = thread.pid
   puts stdout.read.chomp
end
Konrad Reiche
źródło
3
A dla bardziej precyzyjną kontrolę, jak uchwyty połączeń STDIN, STDOUT, STDERR, należy rozważyć Open3.popen3zamiast; np. patrz stackoverflow.com/a/10922097/258662
cboettig
1
Dziękuję za wspomnienie, że backticks obsługują interpolację łańcuchów, co rozwiązało mój problem.
adg
244

Oto schemat blokowy oparty na tej odpowiedzi . Zobacz także: używanie scriptdo emulacji terminala .

wprowadź opis zdjęcia tutaj

Ian
źródło
3
To nie jest takie proste. W moim przypadku „było OK (i trzeba) blokować aż do zakończenia procesu”, a następnie użyć popen3 do sprawdzenia wyjść STDOUT / STDERR.
Nakilon,
Zawsze możesz wywołać nieblokujące wywołanie (efektywnie) bloku, zawijając je w pętli while. Nie można tak łatwo wykonać połączenia blokującego w połączenie nieblokujące.
Ian
106

Robią różne rzeczy. execzastępuje bieżący proces nowym procesem i nigdy nie powraca . systemwywołuje inny proces i zwraca jego wartość wyjściową do bieżącego procesu. Użycie backticks wywołuje inny proces i zwraca wynik tego procesu do bieżącego procesu.

William Pursell
źródło