Wywoływanie poleceń powłoki z Ruby

głosy
862

Jak mogę zadzwonić poleceń powłoki z wnętrza programu Ruby? Jak mogę dostać następnie wyjście z tych poleceń z powrotem w Ruby?

Utwórz 05/08/2008 o 13:56
źródło użytkownik
W innych językach...                            


20 odpowiedzi

głosy
1k

To wyjaśnienie jest oparty na skomentował skryptu Ruby od mojego przyjaciela. Jeśli chcesz poprawić skrypt, nie krępuj się go zaktualizować na ogniwie.

Po pierwsze, należy pamiętać, że gdy Ruby woła do powłoki, to zwykle nazywa /bin/sh, nie atakujących. Niektóre Bash składnia nie jest obsługiwana przez /bin/shwszystkich systemach.

Oto sposoby, aby wykonać skrypt:

cmd = "echo 'hi'" # Sample string that can be used
  1. Kernel#` , Powszechnie nazywane backticks - `cmd`

    To jest podobnie jak wiele innych języków, w tym Bash, PHP i Perl.

    Zwraca wynik polecenia powłoki.

    Dokumenty: http://ruby-doc.org/core/Kernel.html#method-i-60

    value = `echo 'hi'`
    value = `#{cmd}`
    
  2. Wbudowany w składni, %x( cmd )

    Po xznaku jest ogranicznik, który może być dowolny znak. Jeśli separator jest jednym z bohaterów (, [, {, lub <, dosłowne składa się ze znaków aż do ogranicznika dopasowanie zamknięcia, z uwzględnieniem zagnieżdżonych par ogranicznik. Dla wszystkich innych ograniczników, dosłowne zawiera znaki aż do następnego wystąpienia znaku separatora. Interpolacja String #{ ... }jest dozwolone.

    Zwraca wynik polecenia powłoki, podobnie jak backticks.

    Dokumenty: http://www.ruby-doc.org/docs/ProgrammingRuby/html/language.html

    value = %x( echo 'hi' )
    value = %x[ #{cmd} ]
    
  3. Kernel#system

    Wykonuje daną komendę w podpowłoce.

    Zwraca truejeśli polecenie zostało znalezione i przebiegały pomyślnie, falseinaczej.

    Dokumenty: http://ruby-doc.org/core/Kernel.html#method-i-system

    wasGood = system( "echo 'hi'" )
    wasGood = system( cmd )
    
  4. Kernel#exec

    Zastępuje bieżący proces uruchomiony przez daną komendę zewnętrzną.

    Zwraca żaden obecny proces otrzymuje i nigdy nie trwa.

    Dokumenty: http://ruby-doc.org/core/Kernel.html#method-i-exec

    exec( "echo 'hi'" )
    exec( cmd ) # Note: this will never be reached because of the line above
    

Oto kilka dodatkowych rad: $?, która jest taka sama jak $CHILD_STATUS, dostęp status ostatniego systemu wykonywane polecenie jeśli używasz odwrócone, pojedyncze apostrofy, system()lub %x{}. Następnie można uzyskać dostęp do exitstatusi pidwłaściwości:

$?.exitstatus

Aby uzyskać więcej czytania na stronie internetowej:

Odpowiedział 05/08/2008 o 15:42
źródło użytkownik

głosy
150

Tak jak lubię to zrobić za pomocą %xdosłowny, co sprawia, że jest łatwy w użyciu cytatów w poleceniu, tak jak (i czytelny!):

directorylist = %x[find . -name '*test.rb' | sort]

Który w tym przypadku będzie zapełnić listę plików z wszystkich plików testowych w bieżącym katalogu, który można przetwarzać zgodnie z oczekiwaniami:

directorylist.each do |filename|
  filename.chomp!
  # work with file
end
Odpowiedział 05/08/2008 o 15:08
źródło użytkownik

głosy
140

Oto schemat blokowy na podstawie tej odpowiedzi . Zobacz także, używając scriptdo emulacji terminala .

wprowadzić opis obrazu tutaj

Odpowiedział 19/05/2016 o 17:01
źródło użytkownik

głosy
58

Oto najlepszy artykuł moim zdaniem o uruchamianie skryptów powłoki w Ruby: „ 6 sposobów na uruchamianie poleceń powłoki w Ruby ”.

Jeśli tylko trzeba uzyskać odwrócone, pojedyncze apostrofy używać funkcji.

Potrzebowałem bardziej zaawansowanych rzeczy jak standardowe wyjście i stderr więc użyłem Open4 gem. Masz wszystkie metody wyjaśniono tam.

Odpowiedział 02/09/2008 o 12:05
źródło użytkownik

głosy
31

Moim ulubionym jest Open3

  require "open3"

  Open3.popen3('nroff -man') { |stdin, stdout, stderr| ... }
Odpowiedział 18/09/2008 o 18:47
źródło użytkownik

głosy
23

Niektóre rzeczy do przemyślenia przy wyborze pomiędzy tymi mechanizmami są:

  1. Czy po prostu chcesz zrobić stdout lub stderr jak trzeba dobrze? lub nawet oddzielić?
  2. Jak duża jest twoja moc? Chcesz trzymać całą wynik w pamięci?
  3. Czy chcesz przeczytać niektóre z wyjściem podczas gdy podproces nadal działa?
  4. Czy trzeba kody wynikowe?
  5. Czy potrzebny jest obiekt, który reprezentuje rubinowy proces i pozwala zabić go na żądanie?

Może trzeba coś od prostych backticks ( ``), system (), a IO.popendo pełnowymiarową Kernel.fork/ Kernel.execz IO.pipei IO.select.

Można też rzucić limity czasu w mix jeśli podproces trwa zbyt długo, aby wykonać.

Niestety, bardzo wiele zależy .

Odpowiedział 07/08/2008 o 06:10
źródło użytkownik

głosy
19

Jeszcze jedna opcja:

Kiedy ty:

  • Potrzebują stderr jak i stdout
  • nie może / nie użyje Open3 / Open4 (rzucać wyjątków w NetBeans na moim Macu, nie wiem dlaczego)

Można użyć powłoki przekierowanie:

puts %x[cat bogus.txt].inspect
  => ""

puts %x[cat bogus.txt 2>&1].inspect
  => "cat: bogus.txt: No such file or directory\n"

2>&1Składnia działa na Linux , Mac i systemu Windows od wczesnych dni od MS-DOS.

Odpowiedział 16/06/2010 o 03:13
źródło użytkownik

głosy
15

I na pewno nie jestem ekspertem Ruby, ale dam mu szansę:

$ irb 
system "echo Hi"
Hi
=> true

Należy również być w stanie robić takie rzeczy jak:

cmd = 'ls'
system(cmd)
Odpowiedział 05/08/2008 o 14:24
źródło użytkownik

głosy
11

Powyższe odpowiedzi są już całkiem super, ale naprawdę chcę podzielić się następujący artykuł: „Podsumowanie 6 sposobów uruchamiania poleceń powłoki w Ruby

Zasadniczo, to mówi nam:

Kernel#exec:

exec 'echo "hello $HOSTNAME"'

systemoraz $?:

system 'false' 
puts $?

Backticks ( `):

today = `date`

IO#popen:

IO.popen("date") { |f| puts f.gets }

Open3#popen3 - stdlib:

require "open3"
stdin, stdout, stderr = Open3.popen3('dc') 

Open4#popen4 -- klejnot:

require "open4" 
pid, stdin, stdout, stderr = Open4::popen4 "false" # => [26327, #<IO:0x6dff24>, #<IO:0x6dfee8>, #<IO:0x6dfe84>]
Odpowiedział 07/06/2013 o 03:07
źródło użytkownik

głosy
7

Jeśli naprawdę potrzebujesz Bash, za notatki w „najlepszym” odpowiedź.

Po pierwsze, należy pamiętać, że gdy Ruby woła do powłoki, to zwykle nazywa /bin/sh, nie atakujących. Niektóre Bash składnia nie jest obsługiwana przez /bin/shwszystkich systemach.

Jeśli trzeba użyć Bash, włóż bash -c "your Bash-only command"do środka od pożądanego sposobu dzwonisz.

quick_output = system("ls -la")

quick_bash = system("bash -c 'ls -la'")

Testować:

system("echo $SHELL") system('bash -c "echo $SHELL"')

Lub jeśli używasz istniejący plik skryptu (np script_output = system("./my_script.sh")) Ruby powinien honorować shebang, ale zawsze można użyć system("bash ./my_script.sh"), aby upewnić się (choć może być niewielki narzut z /bin/shsystemem /bin/bash, to prawdopodobnie nie zauważy.

Odpowiedział 02/06/2017 o 20:14
źródło użytkownik

głosy
7

Można również użyć operatorów lewy apostrof ( `), podobne do Perl:

directoryListing = `ls /`
puts directoryListing # prints the contents of the root directory

Poręczny, jeśli chcesz coś prostego.

Która metoda chcesz użyć zależy od dokładnie to, co starasz się osiągnąć; sprawdzić dokumenty dla więcej szczegółów na temat różnych metod.

Odpowiedział 05/08/2008 o 14:57
źródło użytkownik

głosy
5

Nie zapomnij o spawnpolecenie, aby utworzyć proces w tle, aby wykonać określone polecenia. Można nawet poczekać do jego zakończenia korzystania z Processklasy i zwracana pid:

pid = spawn("tar xf ruby-2.0.0-p195.tar.bz2")
Process.wait pid

pid = spawn(RbConfig.ruby, "-eputs'Hello, world!'")
Process.wait pid

Doc mówi: Ta metoda jest podobna do #system, ale nie czekać na polecenia do końca.

Odpowiedział 04/11/2015 o 15:04
źródło użytkownik

głosy
5

Korzystanie odpowiedź tutaj i połączone w odpowiedzi Mihai, w Stworzyłam funkcję, która spełnia następujące wymagania:

  1. Starannie oddaje STDOUT i stderr więc nie „przeciek”, gdy mój skrypt jest uruchamiany z konsoli.
  2. Pozwala argumenty mają być przekazywane do powłoki jako tablicę, więc nie ma potrzeby martwić się o ucieczce.
  3. Oddaje stan wyjścia polecenia więc jasne jest, gdy wystąpił błąd.

Jako bonus, ten będzie również powrót STDOUT w przypadkach, w których z powodzeniem wyjść komenda powłoki (0) i stawia wszystko na standardowe wyjście. W ten sposób różni się od system, które po prostu zwraca truesię w takich przypadkach.

Kod następująco. Specyficzna funkcja system_quietly:

require 'open3'

class ShellError < StandardError; end

#actual function:
def system_quietly(*cmd)
  exit_status=nil
  err=nil
  out=nil
  Open3.popen3(*cmd) do |stdin, stdout, stderr, wait_thread|
    err = stderr.gets(nil)
    out = stdout.gets(nil)
    [stdin, stdout, stderr].each{|stream| stream.send('close')}
    exit_status = wait_thread.value
  end
  if exit_status.to_i > 0
    err = err.chomp if err
    raise ShellError, err
  elsif out
    return out.chomp
  else
    return true
  end
end

#calling it:
begin
  puts system_quietly('which', 'ruby')
rescue ShellError
  abort "Looks like you don't have the `ruby` command. Odd."
end

#output: => "/Users/me/.rvm/rubies/ruby-1.9.2-p136/bin/ruby"
Odpowiedział 21/02/2012 o 00:36
źródło użytkownik

głosy
5

Możemy to osiągnąć na wiele sposobów.

Korzystanie Kernel#exec, nic po wykonaniu tego polecenia:

exec('ls ~')

Za pomocą backticks or %x

`ls ~`
=> "Applications\nDesktop\nDocuments"
%x(ls ~)
=> "Applications\nDesktop\nDocuments"

Używając Kernel#systempolecenia, zwraca truejeśli się powiedzie, falsejeśli powiedzie się i wraca nil, jeśli wykonanie polecenia nie powiedzie się:

system('ls ~')
=> true
Odpowiedział 19/02/2012 o 19:07
źródło użytkownik

głosy
4

Najprostszym sposobem jest na przykład:

reboot = `init 6`
puts reboot
Odpowiedział 30/03/2017 o 18:13
źródło użytkownik

głosy
3
  • backticks `metoda jest najprostszym jeden zadzwonić poleceń powłoki z rubinem. Zwraca wynik polecenia powłoki.

     url_request = 'http://google.com'
     result_of_shell_command = `curl #{url_request}`
    
Odpowiedział 16/02/2017 o 09:58
źródło użytkownik

głosy
3

Jeśli masz bardziej skomplikowany niż w przypadku wspólnego (które nie mogą być traktowane z ``), a następnie sprawdzić Kernel.spawn() tutaj . To wydaje się być najbardziej generic / pełni funkcjonalny zapewnia photography Ruby wykonywanie poleceń zewnętrznych.

Na przykład można użyć do:

  • tworzenie grup procesowych (Windows)
  • przekierowanie in, out, błąd w plikach / each-other.
  • zestaw env vars, umask
  • zmienić dir przed wykonaniem polecenia
  • granicach określonych zasobów dla CPU / danych / ...
  • Zrobić wszystko, co można zrobić z innymi opcjami w innych odpowiedzi, ale z większą ilością kodu.

Oficjalna dokumentacja rubin ma wystarczająco dobrych przykładów.

env: hash
  name => val : set the environment variable
  name => nil : unset the environment variable
command...:
  commandline                 : command line string which is passed to the standard shell
  cmdname, arg1, ...          : command name and one or more arguments (no shell)
  [cmdname, argv0], arg1, ... : command name, argv[0] and zero or more arguments (no shell)
options: hash
  clearing environment variables:
    :unsetenv_others => true   : clear environment variables except specified by env
    :unsetenv_others => false  : dont clear (default)
  process group:
    :pgroup => true or 0 : make a new process group
    :pgroup => pgid      : join to specified process group
    :pgroup => nil       : dont change the process group (default)
  create new process group: Windows only
    :new_pgroup => true  : the new process is the root process of a new process group
    :new_pgroup => false : dont create a new process group (default)
  resource limit: resourcename is core, cpu, data, etc.  See Process.setrlimit.
    :rlimit_resourcename => limit
    :rlimit_resourcename => [cur_limit, max_limit]
  current directory:
    :chdir => str
  umask:
    :umask => int
  redirection:
    key:
      FD              : single file descriptor in child process
      [FD, FD, ...]   : multiple file descriptor in child process
    value:
      FD                        : redirect to the file descriptor in parent process
      string                    : redirect to file with open(string, "r" or "w")
      [string]                  : redirect to file with open(string, File::RDONLY)
      [string, open_mode]       : redirect to file with open(string, open_mode, 0644)
      [string, open_mode, perm] : redirect to file with open(string, open_mode, perm)
      [:child, FD]              : redirect to the redirected file descriptor
      :close                    : close the file descriptor in child process
    FD is one of follows
      :in     : the file descriptor 0 which is the standard input
      :out    : the file descriptor 1 which is the standard output
      :err    : the file descriptor 2 which is the standard error
      integer : the file descriptor of specified the integer
      io      : the file descriptor specified as io.fileno
  file descriptor inheritance: close non-redirected non-standard fds (3, 4, 5, ...) or not
    :close_others => false : inherit fds (default for system and exec)
    :close_others => true  : dont inherit (default for spawn and IO.popen)
Odpowiedział 11/12/2015 o 14:57
źródło użytkownik

głosy
1

Biorąc pod komendę np attrib

require 'open3'

a="attrib"
Open3.popen3(a) do |stdin, stdout, stderr|
  puts stdout.read
end

Odkryłem, że choć metoda ta nie jest tak niezapomniany, jak na przykład system ( „thecommand”) lub thecommand w backticks, dobrą rzeczą na temat tej metody w porównaniu z innymi metodami jest np .. backticks nie wydaje się, by pozwolił mi „puts "komenda biegnę / przechowywać polecenia Chcę uruchomić w zmiennej i systemu («thecommand») wydaje się nie pozwól mi wyjście. Metoda ta pozwala mi robić obie te rzeczy, a to pozwala mi dostęp stdin, stdout i stderr niezależnie.

https://blog.bigbinary.com/2012/10/18/backtick-system-exec-in-ruby.html

http://ruby-doc.org/stdlib-2.4.1/libdoc/open3/rdoc/Open3.html

Odpowiedział 19/12/2017 o 05:54
źródło użytkownik

głosy
0

Naprawdę nie odpowiedź, ale może ktoś znajdzie to użyteczne, a jego odnośnie do tego.

Podczas korzystania TK GUI w systemie Windows, a u trzeba zadzwonić poleceń powłoki z rubyw, u będzie zawsze irytujące okno cmd pojawiały się na mniej niż sekundę.

Aby tego uniknąć można korzystać

WIN32OLE.new('Shell.Application').ShellExecute('ipconfig > log.txt','','','open',0)

lub

WIN32OLE.new('WScript.Shell').Run('ipconfig > log.txt',0,0)

Zarówno będzie przechowywać ipconfig za wyjście wewnątrz „log.txt”, ale nie ma okna pojawi się.

U będą musiały require 'win32ole'wewnątrz skryptu.

system(), exec()I spawn()będzie wszystko pop-up, które irytujące okna przy użyciu TK i rubyw.

Odpowiedział 05/07/2018 o 12:55
źródło użytkownik

głosy
-1

Oto jeden fajne, że mogę używać w skrypcie Ruby on OS X (tak, że mogę uruchomić skrypt i uzyskać aktualizację nawet po przełączeniu z dala od okna):

cmd = %Q|osascript -e 'display notification "Server was reset" with title "Posted Update"'|
system ( cmd )
Odpowiedział 14/10/2014 o 21:12
źródło użytkownik

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more