Wie rufe ich Shell-Befehle aus einem Ruby-Programm heraus auf? Wie bekomme ich dann die Ausgabe dieser Befehle in Ruby zurück?
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
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.
Der einfachste Weg ist zum Beispiel:
reboot = `init 6`
puts reboot
Mit den Antworten hier und in Mihais Antwort verlinkt, habe ich eine Funktion zusammengestellt, die diese Anforderungen erfüllt:
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"
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}`
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:
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)
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
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.
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 )