Shell-Befehle von Ruby aus aufrufen

  • Wie rufe ich Shell-Befehle aus einem Ruby-Programm heraus auf? Wie bekomme ich dann die Ausgabe dieser Befehle in Ruby zurück?

    06 March 2015
    Andrew Marshallrickyduck
19 answers
  • Wir können es auf mehrere Arten erreichen.

    Mit Kernel#exec wird nichts ausgeführt, nachdem dieser Befehl ausgeführt wurde:

     exec('ls ~')
     

    Verwenden von backticks or %x

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

    Mit dem Befehl Kernel#system wird true zurückgegeben, falls erfolgreich, false, falls dies nicht erfolgreich war, und nil, wenn die Befehlsausführung fehlschlägt:

     system('ls ~')
    => true
     
    11 October 2013
    the Tin ManEqbal
  • Vergessen Sie nicht den Befehl spawn, um einen Hintergrundprozess für die Ausführung des angegebenen Befehls zu erstellen. Sie können sogar mit der Klasse Process und dem zurückgegebenen pid warten:

     pid = spawn("tar xf ruby-2.0.0-p195.tar.bz2")
    Process.wait pid
    
    pid = spawn(RbConfig.ruby, "-eputs'Hello, world!'")
    Process.wait pid
     

    The doc sagt: Diese Methode ähnelt #system, wartet jedoch nicht, bis der Befehl beendet ist.

    04 November 2015
    MonsieurDart
  • Der einfachste Weg ist zum Beispiel:

     reboot = `init 6`
    puts reboot
     
    30 March 2017
    Alex Lorsung
  • Mit den Antworten hier und in Mihais Antwort verlinkt, habe ich eine Funktion zusammengestellt, die diese Anforderungen erfüllt:

    1. Nimmt STDOUT und STDERR sauber auf Sie "lecken" also nicht, wenn mein Skript von der Konsole aus ausgeführt wird.
    2. Ermöglicht, dass Argumente als Array an die Shell übergeben werden, sodass Sie sich keine Gedanken über die Flucht machen müssen.
    3. Erfasst den Exit-Status des Befehls, damit klar ist, wann ein Fehler aufgetreten ist.

    Als Bonus gilt dies als Bonus man wird auch STDOUT zurückgeben, wenn der Shell-Befehl erfolgreich beendet wird (0) und alles auf STDOUT setzt. Auf diese Weise unterscheidet es sich von system, das in solchen Fällen lediglich true zurückgibt.

    Code folgt. Die spezifische Funktion ist 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"
     
    11 October 2013
    the Tin ManEqbal
    • backticks `Methode ist die einfachste Methode, um Shell-Befehle von Ruby aus aufzurufen. Es gibt das Ergebnis des Shell-Befehls zurück.

        url_request = 'http://google.com'
       result_of_shell_command = `curl #{url_request}`
       
    16 February 2017
    ysk
  • Wenn Sie einen komplexeren Fall haben als der gewöhnliche Fall (der nicht mit `` behandelt werden kann), lesen Sie Kernel.spawn() hier . Dies scheint das allgemeinste / umfassendste Feature zu sein, das stock Ruby für die Ausführung externer Befehle zur Verfügung stellt.

    E.g. Sie können es verwenden, um:

    • Prozessgruppen zu erstellen (Windows)
    • Weiterleiten in / out, Fehler in Dateien / jedes andere.
    • setze die Umgebung, umask
    • Ändere das Verzeichnis, bevor Sie den Befehl ausführen
    • Ressourcengrenzen für CPU / setzen data /...
    • Führen Sie alles aus, was mit anderen Optionen in anderen Antworten möglich ist, jedoch mit mehr Code.

    Die offizielle Ruby-Dokumentation ist gut genug Beispiele.

     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)
     
    11 December 2015
    KashyapRahul Narkhede
  • Wenn ein Befehl angegeben wurde, z. B. attrib

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

    habe ich festgestellt, dass diese Methode zwar isn 'ist t so einprägsam wie z System ("der Befehl") oder der Befehl in Backticks, eine gute Sache über diese Methode im Vergleich zu anderen Methoden .. ist z. Backticks scheint mir nicht zu erlauben, den Befehl, den ich ausführen möchte, zu speichern und den Befehl, den ich ausführen möchte, in einer Variablen zu speichern. Das System ("thecommand") scheint mir die Ausgabe nicht zu ermöglichen. Mit dieser Methode kann ich beides tun, und ich kann unabhängig auf stdin, stdout und stderr zugreifen.

    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

    11 April 2018
    brainbagbarlop
  • Nicht wirklich eine Antwort, aber vielleicht wird jemand dies als nützlich erachten und diesbezüglich.

    Wenn Sie TK GUI unter Windows verwenden, müssen Sie shell aufrufen Befehle von Rubyw, u wird immer ein ärgerliches Cmd-Fenster für weniger als eine Sekunde angezeigt.

    Um dies zu vermeiden, können Sie

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

    oder

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

    Beide werden dies tun Speichern Sie die Ausgabe von ipconfig in 'log.txt', aber es werden keine Fenster angezeigt.

    U muss in Ihrem Skript require 'win32ole' sein.

    system(), exec() und spawn() werden bei der Verwendung von TK und rubyw alle in diesem lästigen Fenster angezeigt.

    05 July 2018
    lucaortis
  • Hier ist eine coole Version, die ich in einem Ruby-Skript unter OS X verwende (damit ich ein Skript starten und ein Update erhalten kann, auch nachdem ich mich vom Fenster entfernt habe):

     cmd = %Q|osascript -e 'display notification "Server was reset" with title "Posted Update"'|
    system ( cmd )
     
    15 October 2014
    JayCrossler