Volání příkazy shellu z Ruby

hlasů
862

Jak mohu volat příkazy shellu zevnitř programu Ruby? Jak mohu pak se výstup z těchto příkazů zpět do Ruby?

Položena 05/08/2008 v 13:56
zdroj uživatelem
V jiných jazycích...                            


20 odpovědí

hlasů
1k

Toto vysvětlení je založeno na komentovanou Ruby skript z mého přítele. Chcete-li zlepšit scénář, klidně jej aktualizovat v odkazu.

Za prvé, na vědomí, že když Ruby volá do shellu, to obvykle požaduje /bin/sh, ne Bash. Některé syntax Bash není podporován /bin/shna všech systémech.

Zde jsou způsoby, jak spustit shell skript:

cmd = "echo 'hi'" # Sample string that can be used
  1. Kernel#` , Běžně nazývaná backticks - `cmd`

    To je stejně jako mnoho jiných jazyků, včetně Bash, PHP a Perl.

    Vrací výsledek příkazu shell.

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

    value = `echo 'hi'`
    value = `#{cmd}`
    
  2. Zabudovaný v syntaxi, %x( cmd )

    V návaznosti na xznak je oddělovač, který může být libovolný znak. V případě, že oddělovač je jeden z charakterů (, [, {nebo <, doslovný se skládá z postav až k odpovídající uzavírací oddělovač, s přihlédnutím k vnořených oddělovačů páry. Pro všechny ostatní oddělovače, doslovný obsahuje znaky až do dalšího výskytu oddělovacím znakem. Interpolace řetězec #{ ... }je povoleno.

    Vrací výsledek příkazu shell, stejně jako backticks.

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

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

    Provede zadaný příkaz v subshellu.

    Vrátí true-li se zjistilo, že řídící a proběhl úspěšně, falsejinak.

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

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

    Nahradí aktuální proces pracuje příslušný externí příkaz.

    Vrací nic, současný proces je nahrazen a nikdy pokračuje.

    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
    

Zde je několik rad navíc: $?, která je stejná jako $CHILD_STATUS, přistupuje stav posledního systému spuštěn příkaz, pokud používáte backticks, system()nebo %x{}. Poté můžete přistupovat k exitstatusa pidvlastnosti:

$?.exitstatus

Další čtení viz:

Odpovězeno 05/08/2008 v 15:42
zdroj uživatelem

hlasů
150

Způsob, jak se mi líbí, jak to udělat, je pomocí %xdoslovný, což usnadňuje použití uvozovek v příkazu, tak jako (a čitelný!):

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

Který v tomto případě bude naplnit seznam souborů se všemi zkušebními soubory v aktuálním adresáři, který dokáže zpracovat podle očekávání:

directorylist.each do |filename|
  filename.chomp!
  # work with file
end
Odpovězeno 05/08/2008 v 15:08
zdroj uživatelem

hlasů
140

Zde je vývojový diagram na základě této odpovědi . Viz také používat scriptk emulaci terminálu .

zadejte popis obrázku zde

Odpovězeno 19/05/2016 v 17:01
zdroj uživatelem

hlasů
58

Zde je nejlepší článek podle mého názoru o spuštění skripty Ruby: „ 6 způsobů, jak spustit příkazy pro Ruby “.

Pokud si jen potřebujete dostat výstup použití backticks.

Potřeboval jsem pokročilejší věci, jako STDOUT a STDERR a tak jsem použil Open4 gem. Máte všechny metody zde vysvětleny.

Odpovězeno 02/09/2008 v 12:05
zdroj uživatelem

hlasů
31

Můj oblíbený je Open3

  require "open3"

  Open3.popen3('nroff -man') { |stdin, stdout, stderr| ... }
Odpovězeno 18/09/2008 v 18:47
zdroj uživatelem

hlasů
23

Některé věci myslet při volbě mezi těmito mechanismy jsou:

  1. Myslíte si jen chcete stdout nebo potřebujete stderr stejně? nebo dokonce vyloučí?
  2. Jak velký je váš výkon? Chcete držet celý výsledek v paměti?
  3. Myslíte si přečíst některé z vašich výstupu, zatímco podproces je stále běží?
  4. Potřebujete výsledek kódy?
  5. Potřebujete objekt ruby, který představuje proces a umožňuje ji zabít na vyžádání?

Možná budete potřebovat cokoli od jednoduchých backticks ( ``), systém () a IO.popenna full-foukané Kernel.fork/ Kernel.execs IO.pipea IO.select.

Můžete také chtít, aby hodit prodlevám do mixu, pokud podproces trvá příliš dlouho spustit.

Bohužel to velmi záleží .

Odpovězeno 07/08/2008 v 06:10
zdroj uživatelem

hlasů
19

A ještě jedna možnost:

Když vás:

  • Potřebujete stderr stejně jako stdout
  • Nelze / nebude používat Open3 / Open4 (házejí výjimky v NetBeans na mém Macu, nemám tušení, proč)

Můžete použít přesměrování shell:

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

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

2>&1Syntaxe funguje na Linuxu , Mac a Windows od prvních dnů MS-DOS.

Odpovězeno 16/06/2010 v 03:13
zdroj uživatelem

hlasů
15

Jsem rozhodně není expert Ruby, ale budu to zkusit:

$ irb 
system "echo Hi"
Hi
=> true

Také byste měli být schopni dělat věci jako:

cmd = 'ls'
system(cmd)
Odpovězeno 05/08/2008 v 14:24
zdroj uživatelem

hlasů
11

Odpovědi uvedené jsou již poměrně velký, ale opravdu chci sdílet následující shrnutí článku: „ 6 způsoby, jak spustit příkazy pro Ruby

V podstatě, to nám říká:

Kernel#exec:

exec 'echo "hello $HOSTNAME"'

systema $?:

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 - perla:

require "open4" 
pid, stdin, stdout, stderr = Open4::popen4 "false" # => [26327, #<IO:0x6dff24>, #<IO:0x6dfee8>, #<IO:0x6dfe84>]
Odpovězeno 07/06/2013 v 03:07
zdroj uživatelem

hlasů
7

Pokud opravdu potřebujete Bash, na poznámce v „nejlepší“ odpověď.

Za prvé, na vědomí, že když Ruby volá do shellu, to obvykle požaduje /bin/sh, ne Bash. Některé syntax Bash není podporován /bin/shna všech systémech.

Pokud potřebujete použít Bash, vložka bash -c "your Bash-only command"uvnitř požadovaného volání metody.

quick_output = system("ls -la")

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

Testovat:

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

Nebo pokud používáte existující soubor skriptu (např script_output = system("./my_script.sh")) Ruby by měl ctít shebang, ale můžete vždy použít system("bash ./my_script.sh"), aby se ujistil (i když tam může dojít k mírnému režie od /bin/shspuštění /bin/bash, pravděpodobně ani nevšimnete.

Odpovězeno 02/06/2017 v 20:14
zdroj uživatelem

hlasů
7

Můžete také použít operátory backtick ( `), podobně jako Perl:

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

Užitečné, pokud budete potřebovat něco jednoduchého.

Kterou metodu chcete použít, závisí na přesně to, co se snažíte dosáhnout; zkontrolovat dokumenty pro více informací o různých metod.

Odpovězeno 05/08/2008 v 14:57
zdroj uživatelem

hlasů
5

Nezapomeňte na spawnpříkaz vytvořit proces na pozadí vykonat zadaný příkaz. Můžete dokonce čekat na jeho dokončení pomocí Processtřídy a vrací 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

Doktor říká: Tato metoda je podobná #system, ale to nebude čekat na dokončení příkazu.

Odpovězeno 04/11/2015 v 15:04
zdroj uživatelem

hlasů
5

Používání odpovědi tady a propojeny Mihai odpověď, dal jsem dohromady funkce, která splňuje tyto požadavky:

  1. Přehledně zachycuje STDOUT a STDERR a tak nemají „únik“, když je můj skript spustit z konzole.
  2. Umožňuje argumenty, které mají být předány k plášti jako pole, takže není třeba se obávat úniku.
  3. Zachycuje stav ukončení příkazu, takže je jasné, kdy došlo k chybě.

Jako bonus, tenhle bude také vrátit STDOUT v případech, kdy úspěšně příkaz shell východy (0) a dá něco na STDOUT. Tímto způsobem, se liší od system, které jednoduše vrátí truev takových případech.

Kód následujícím způsobem. Specifická funkce je 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"
Odpovězeno 21/02/2012 v 00:36
zdroj uživatelem

hlasů
5

Můžeme ho dosáhnout několika způsoby.

Používání Kernel#exec, co po tomto provedení příkazu:

exec('ls ~')

Použitím backticks or %x

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

Pomocí Kernel#systempříkazu, vrátí true-li úspěšný, falsepokud neúspěšné a vrátí nil, pokud selže vykonávání příkazu:

system('ls ~')
=> true
Odpovězeno 19/02/2012 v 19:07
zdroj uživatelem

hlasů
4

Nejjednodušší způsob, jak je, například:

reboot = `init 6`
puts reboot
Odpovězeno 30/03/2017 v 18:13
zdroj uživatelem

hlasů
3
  • backticks `metoda je nejjednodušší, kdo volat příkazy shellu z ruby. Vrací výsledek příkazu shell.

     url_request = 'http://google.com'
     result_of_shell_command = `curl #{url_request}`
    
Odpovězeno 16/02/2017 v 09:58
zdroj uživatelem

hlasů
3

Pokud máte složitější případ, než je běžný případ (které nemohou být řešeny s ``), pak se podívejte Kernel.spawn() zde . To se zdá být nejvíce generické / plnohodnotná poskytnuty akciové Ruby spouštět externí příkazy.

Například můžete použít k:

  • Vytvoření skupiny procesů (Windows)
  • přesměrovat in, out, chyba k souborům / each-jiný.
  • set env proměnnými, umask
  • změnit dir před spuštěním příkazu
  • Limity set prostředků pro CPU / data / ...
  • Dělat vše, co lze udělat s dalšími možnostmi v jiných odpovědích, ale s větším kódem.

Oficiální ruby dokumentace má dost dobrých příkladů.

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)
Odpovězeno 11/12/2015 v 14:57
zdroj uživatelem

hlasů
1

Vzhledem k tomu příkaz např attrib

require 'open3'

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

Zjistil jsem, že i když tato metoda není tak památný jako například systém ( „thecommand“) nebo thecommand v backticks, dobrá věc o tomto způsobu ve srovnání s jinými metodami .. je např backticks nezdá se, dejte mi ‚uvádí "příkaz spustit / uložit příkaz chci běžet v proměnné, a systém (‚thecommand‘), nezdá se, že mě nech výstup. Zatímco tato metoda mi umožňuje provést obě tyto věci, a to mi umožňuje přístup stdin, stdout a stderr samostatně.

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

Odpovězeno 19/12/2017 v 05:54
zdroj uživatelem

hlasů
0

Není opravdu odpověď, ale možná někdo najde to užitečné, a jeho o to.

Při použití TK GUI pro Windows, a u je třeba volat příkazy shellu z rubyw, bude u muset vždy nepříjemné okna cmd vyskakování za méně než chvilku.

Aby se tomu zabránilo můžete používat

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

nebo

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

Oba budou ukládat ipconfig je výstup uvnitř ‚log.txt‘, ale žádná okna přijde.

U muset require 'win32ole'uvnitř skriptu.

system(), exec()A spawn()budou všechny pop-up, který otravné okna při použití TK a rubyw.

Odpovězeno 05/07/2018 v 12:55
zdroj uživatelem

hlasů
-1

Tady je kliďas, který používám na ruby ​​skript na OS X (takže můžu začít skript a získat aktuální informace i po přepínání od okna):

cmd = %Q|osascript -e 'display notification "Server was reset" with title "Posted Update"'|
system ( cmd )
Odpovězeno 14/10/2014 v 21:12
zdroj uživatelem

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