Uruchamianie poleceń wiersza poleceń w skrypcie Ruby

92

Czy istnieje sposób uruchamiania poleceń wiersza poleceń za pośrednictwem Rubiego? Próbuję stworzyć mały program w Rubim, który dzwoniłby i odbierał / wysyłał przez programy wiersza poleceń, takie jak „screen”, „rcsz” itp.

Byłoby wspaniale, gdybym mógł to wszystko powiązać z Rubim (zapleczem MySQL itp.)

geetfun
źródło
Możliwy duplikat poleceń powłoki Calling z Ruby
ymoreau

Odpowiedzi:

209

Tak. Jest kilka sposobów:


za. Użyj %xlub '' ':

%x(echo hi) #=> "hi\n"
%x(echo hi >&2) #=> "" (prints 'hi' to stderr)

`echo hi` #=> "hi\n"
`echo hi >&2` #=> "" (prints 'hi' to stderr)

Te metody zwrócą standardowe wyjście i przekierują stderr do programu.


b. Zastosowanie system:

system 'echo hi' #=> true (prints 'hi')
system 'echo hi >&2' #=> true (prints 'hi' to stderr)
system 'exit 1' #=> nil

Ta metoda zwraca, truejeśli polecenie zakończyło się pomyślnie. Przekierowuje wszystkie dane wyjściowe do programu.


do. Zastosowanie exec:

fork { exec 'sleep 60' } # you see a new process in top, "sleep", but no extra ruby process. 
exec 'echo hi' # prints 'hi'
# the code will never get here.

To zastępuje bieżący proces tym utworzonym przez polecenie.


re. (rubin 1.9) użyj spawn:

spawn 'sleep 1; echo one' #=> 430
spawn 'echo two' #=> 431
sleep 2
# This program will print "two\none".

Ta metoda nie czeka na zakończenie procesu i zwraca PID.


mi. Zastosowanie IO.popen:

io = IO.popen 'cat', 'r+'
$stdout = io
puts 'hi'
$stdout = IO.new 0
p io.read(1)
io.close
# prints '"h"'.

Ta metoda zwróci IOobiekt, który reprezentuje wejście / wyjście nowego procesu. Jest to również obecnie jedyny znany mi sposób przekazywania danych wejściowych do programu.


fa. Użyj Open3(w wersji 1.9.2 i nowszych)

require 'open3'

stdout,stderr,status = Open3.capture3(some_command)
STDERR.puts stderr
if status.successful?
  puts stdout
else
  STDERR.puts "OH NO!"
end

Open3ma kilka innych funkcji do uzyskiwania jawnego dostępu do dwóch strumieni wyjściowych. Jest podobny do popen, ale daje dostęp do stderr.

Adrian
źródło
Bonus trick: io = IO.popen 'cat > out.log', 'r+'; zapisuje dane wyjściowe polecenia do „out.log”
Narfanator,
1
Jakie są zalety i wady każdego z nich. Jak zdecydować, którego użyć? Co powiesz na użycie FileUtils[ ruby-doc.org/stdlib-1.9.3/libdoc/fileutils/rdoc/FileUtils.html] ?
Ava
1
Wykonuję polecenie SVN za pomocą exec. Nie chcę, aby dane wyjściowe exec pojawiały się na konsoli. Chcę go przekierować, aby móc go zapisać jako zmienną i wykonać na tym pewne przetwarzanie. Jak mam to zrobić ?
stack1
2
status.successful? nie działa już u mnie na Ruby 2.4, zmienił się na status.success? :)
DanielG
14

Istnieje kilka sposobów uruchamiania poleceń systemowych w Rubim.

irb(main):003:0> `date /t` # surround with backticks
=> "Thu 07/01/2010 \n"
irb(main):004:0> system("date /t") # system command (returns true/false)
Thu 07/01/2010
=> true
irb(main):005:0> %x{date /t} # %x{} wrapper
=> "Thu 07/01/2010 \n"

Ale jeśli chcesz faktycznie wykonywać dane wejściowe i wyjściowe za pomocą stdin / stdout polecenia, prawdopodobnie będziesz chciał przyjrzeć się IO::popenmetodzie, która specjalnie oferuje tę funkcję .

Mark Rushakoff
źródło
popen działa dobrze, jeśli Twoja aplikacja ma tylko standardowe wyjście. Jeśli potrzebujesz więcej interakcji lub chcesz zrobić coś innego ze stdout, stdin, a zwłaszcza stderr, zechcesz również zajrzeć do open3: ruby-doc.org/core/classes/Open3.html
Paul Rubel
7
 folder = "/"
 list_all_files = "ls -al #{folder}"
 output = `#{list_all_files}`
 puts output
ohho
źródło
2

Tak, jest to z pewnością wykonalne, ale metoda implementacji różni się w zależności od tego, czy dany program „wiersza poleceń” działa w trybie „pełnego ekranu”, czy w trybie wiersza poleceń. Programy napisane dla wiersza poleceń mają tendencję do odczytywania STDIN i zapisywania do STDOUT. Można je wywołać bezpośrednio w Rubim, używając standardowych metod odwrotnych znaków i / lub wywołań system / exec.

Jeśli program działa w trybie „pełnego ekranu”, jak screen lub vi, podejście musi być inne. W przypadku programów takich jak ten powinieneś poszukać implementacji biblioteki „oczekuj” w Ruby. Umożliwi to napisanie scenariusza tego, co spodziewasz się zobaczyć na ekranie i co wysłać, gdy zobaczysz, że te konkretne ciągi pojawiają się na ekranie.

Jest to mało prawdopodobne, aby było to najlepsze podejście i prawdopodobnie powinieneś spojrzeć na to, co próbujesz osiągnąć, i znaleźć odpowiednią bibliotekę / klejnot, aby to zrobić, zamiast próbować zautomatyzować istniejącą aplikację pełnoekranową. Na przykład „ Potrzebujesz pomocy przy komunikacji portu szeregowego w języku Ruby ” dotyczy komunikacji przez port szeregowy, prekursora wybierania numeru, jeśli chcesz to osiągnąć za pomocą wymienionych programów.

Steve Weet
źródło
Prosta wersja Expect jest dostępna w Ruby za pomocą wbudowanego modułu Pty .
Tin Man,
0

Najczęściej używaną metodą jest Open3tutaj używana, moja wersja powyższego kodu edytowana w kodzie z pewnymi poprawkami:

require 'open3'
puts"Enter the command for execution"
some_command=gets
stdout,stderr,status = Open3.capture3(some_command)
STDERR.puts stderr
if status.success?
  puts stdout
else
  STDERR.puts "ERRRR"
end
Keshav Maheshwari
źródło