Κλήση εντολές φλοιού από Ruby

ψήφοι
862

Πώς μπορώ να καλέσετε εντολές του κελύφους από το εσωτερικό ενός προγράμματος Ruby; Πώς μπορώ να πάρει στη συνέχεια έξοδος από αυτές τις εντολές πίσω σε Ruby;

Δημοσιεύθηκε 05/08/2008 στις 13:56
πηγή χρήστη
Σε άλλες γλώσσες...                            


20 απαντήσεις

ψήφοι
1k

Αυτή η εξήγηση βασίζεται σε μια σχολίασε σενάριο Ruby από έναν φίλο του ορυχείου. Αν θέλετε να βελτιώσετε το σενάριο, μη διστάσετε να το ενημερώσετε στο σύνδεσμο.

Πρώτον, σημειώστε ότι όταν Ruby φωνάζει σε ένα κέλυφος, που συνήθως απαιτεί /bin/sh, δεν Bash. Κάποιοι σύνταξη Bash δεν υποστηρίζεται από /bin/shσε όλα τα συστήματα.

Εδώ είναι οι τρόποι για να εκτελέσει ένα σενάριο φλοιού:

cmd = "echo 'hi'" # Sample string that can be used
  1. Kernel#` , Κοινώς ονομάζεται βαρεία - `cmd`

    Αυτό είναι όπως και πολλές άλλες γλώσσες, συμπεριλαμβανομένων Bash, PHP και Perl.

    Επιστρέφει το αποτέλεσμα της εντολής κελύφους.

    Έγγραφα: http://ruby-doc.org/core/Kernel.html#method-i-60

    value = `echo 'hi'`
    value = `#{cmd}`
    
  2. Ενσωματωμένο σύνταξη, %x( cmd )

    Μετά τον xχαρακτήρα είναι ένα διαχωριστικό, το οποίο μπορεί να είναι οποιοδήποτε χαρακτήρα. Αν το διαχωριστικό είναι ένας από τους χαρακτήρες (, [, {, ή <, η γραμματική αποτελείται από τους χαρακτήρες μέχρι τον οριοθέτη που ταιριάζουν κλεισίματος, λαμβανομένων υπόψη των ένθετων ζεύγη οριοθέτησης. Για όλα τα άλλα διαχωριστικά, η γραμματική περιλαμβάνει τους χαρακτήρες μέχρι την επόμενη εμφάνιση του χαρακτήρα οριοθέτησης. String παρεμβολή #{ ... }επιτρέπεται.

    Επιστρέφει το αποτέλεσμα της εντολής κελύφους, όπως ακριβώς και οι βαρεία.

    Έγγραφα: http://www.ruby-doc.org/docs/ProgrammingRuby/html/language.html

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

    Εκτελεί τη συγκεκριμένη εντολή σε ένα υποφλοιό.

    Επιστρέφει trueαν η εντολή βρέθηκε και έτρεξε με επιτυχία, falseδιαφορετικά.

    Έγγραφα: http://ruby-doc.org/core/Kernel.html#method-i-system

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

    Αντικαθιστά την τρέχουσα διαδικασία εκτελώντας την δεδομένη εξωτερική εντολή.

    Επιστρέφει καμία, η τρέχουσα διαδικασία αντικαθίσταται και δεν συνεχίζει.

    Έγγραφα: 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
    

Εδώ είναι μερικές επιπλέον συμβουλές: $?, η οποία είναι η ίδια όπως $CHILD_STATUS, πρόσβαση η κατάσταση του τελευταίου συστήματος εκτελεστεί η εντολή, αν χρησιμοποιείτε τα βαρεία, system()ή %x{}. Στη συνέχεια μπορείτε να αποκτήσετε πρόσβαση στο exitstatusκαι pidιδιότητες:

$?.exitstatus

Για περισσότερες ανάγνωση βλέπε:

Απαντήθηκε 05/08/2008 στις 15:42
πηγή χρήστη

ψήφοι
150

Ο τρόπος που μου αρέσει να το κάνετε αυτό είναι με τη χρήση του %xκυριολεκτική, το οποίο το καθιστά εύκολο στη χρήση εισαγωγικά σε μια εντολή, όπως και τόσοι (και ευανάγνωστο!):

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

Η οποία, στην περίπτωση αυτή, θα συμπληρώσετε λίστα αρχείων με όλα τα αρχεία δοκιμών στον τρέχοντα κατάλογο, που μπορείτε να επεξεργαστείτε όπως αναμενόταν:

directorylist.each do |filename|
  filename.chomp!
  # work with file
end
Απαντήθηκε 05/08/2008 στις 15:08
πηγή χρήστη

ψήφοι
140

Εδώ είναι ένα διάγραμμα ροής που βασίζεται σε αυτή την απάντηση . Δείτε επίσης, τη χρήση scriptγια να μιμηθεί ένα τερματικό .

εισάγετε περιγραφή της εικόνας εδώ

Απαντήθηκε 19/05/2016 στις 17:01
πηγή χρήστη

ψήφοι
58

Εδώ είναι το καλύτερο άρθρο κατά τη γνώμη μου σχετικά με την εκτέλεση δεσμών ενεργειών κελύφους σε Ruby: « 6 τρόποι για να τρέξει Shell Εντολές σε Ruby ».

Αν το μόνο που χρειάζεται για να πάρει τα βαρεία χρήση εξόδου.

Χρειαζόμουν πιο προηγμένες πράγματα, όπως STDOUT και STDERR γι 'αυτό χρησιμοποιείται το Open4 στολίδι. Θα πρέπει όλες οι μέθοδοι εξηγούνται εκεί.

Απαντήθηκε 02/09/2008 στις 12:05
πηγή χρήστη

ψήφοι
31

Το αγαπημένο μου είναι Open3

  require "open3"

  Open3.popen3('nroff -man') { |stdin, stdout, stderr| ... }
Απαντήθηκε 18/09/2008 στις 18:47
πηγή χρήστη

ψήφοι
23

Μερικά πράγματα που πρέπει να σκεφτείτε όταν επιλέγουν μεταξύ αυτών των μηχανισμών είναι:

  1. Μήπως απλά θέλετε stdout ή χρειάζεστε stderr, καθώς; ή ακόμη διαχωριστεί;
  2. Πόσο μεγάλη είναι η έξοδος σας; Θέλετε να κρατήσει ολόκληρο το αποτέλεσμα στη μνήμη;
  3. Θέλετε να διαβάσετε μερικά από έξοδο σας, ενώ η υποεπεξεργασία εξακολουθεί να λειτουργεί;
  4. Χρειάζεστε κωδικούς αποτέλεσμα;
  5. Χρειάζεστε ένα αντικείμενο ρουμπίνι που αντιπροσωπεύει τη διαδικασία και σας επιτρέπει να το σκοτώσει τη ζήτηση;

Μπορεί να χρειαστεί τίποτα από την απλή βαρεία ( ``), το σύστημα (), και IO.popenσε πλήρη άνθηση Kernel.fork/ Kernel.execμε IO.pipeκαι IO.select.

Μπορείτε επίσης να θελήσετε να ρίξει τα χρονικά όρια στο μίγμα, αν ένας υπο-παίρνει πολύ χρόνο για να εκτελέσει.

Δυστυχώς, πάρα πολύ εξαρτάται .

Απαντήθηκε 07/08/2008 στις 06:10
πηγή χρήστη

ψήφοι
19

Μία ακόμη επιλογή:

Οταν εσύ:

  • Πρέπει stderr καθώς και stdout
  • δεν μπορεί / δεν θα χρησιμοποιήσει Open3 / Open4 (ρίχνουν εξαιρέσεις στο NetBeans στο Mac μου, δεν ξέρω γιατί)

Μπορείτε να χρησιμοποιήσετε το κέλυφος ανακατεύθυνση:

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

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

Η 2>&1σύνταξη λειτουργεί σε Linux , Mac και τα Windows από τις πρώτες ημέρες του MS-DOS.

Απαντήθηκε 16/06/2010 στις 03:13
πηγή χρήστη

ψήφοι
15

Δεν είμαι σίγουρα ένας εμπειρογνώμονας Ruby, αλλά εγώ θα το δώσω έναν πυροβολισμό:

$ irb 
system "echo Hi"
Hi
=> true

Θα πρέπει επίσης να είναι σε θέση να κάνουμε τα πράγματα όπως:

cmd = 'ls'
system(cmd)
Απαντήθηκε 05/08/2008 στις 14:24
πηγή χρήστη

ψήφοι
11

Οι παραπάνω απαντήσεις είναι ήδη αρκετά μεγάλη, αλλά πραγματικά θέλω να μοιραστώ την ακόλουθη περίληψη του άρθρου: « 6 τρόποι για να τρέξει Shell Εντολές σε Ruby »

Ουσιαστικά, μας λέει:

Kernel#exec:

exec 'echo "hello $HOSTNAME"'

systemκαι $?:

system 'false' 
puts $?

Βαρεία ( `):

today = `date`

IO#popen:

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

Open3#popen3 - stdlib:

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

Open4#popen4 - ένα στολίδι:

require "open4" 
pid, stdin, stdout, stderr = Open4::popen4 "false" # => [26327, #<IO:0x6dff24>, #<IO:0x6dfee8>, #<IO:0x6dfe84>]
Απαντήθηκε 07/06/2013 στις 03:07
πηγή χρήστη

ψήφοι
7

Αν πραγματικά χρειάζεστε Bash, σύμφωνα με το σημείωμα στην «καλύτερη» απάντηση.

Πρώτον, σημειώστε ότι όταν Ruby φωνάζει σε ένα κέλυφος, που συνήθως απαιτεί /bin/sh, δεν Bash. Κάποιοι σύνταξη Bash δεν υποστηρίζεται από /bin/shσε όλα τα συστήματα.

Εάν πρέπει να χρησιμοποιήσετε το Bash, εισάγετε bash -c "your Bash-only command"στο εσωτερικό της επιθυμητής καλώντας τη μέθοδο σας.

quick_output = system("ls -la")

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

Να δοκιμάσω:

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

Ή εάν εκτελείτε ένα υπάρχον αρχείο script (π.χ. script_output = system("./my_script.sh")) Ruby θα πρέπει να τιμήσει τη δουλεία, αλλά μπορείτε πάντα να χρησιμοποιήσετε system("bash ./my_script.sh")για να βεβαιωθείτε ότι (αν και μπορεί να υπάρχει μια μικρή γενικά από το /bin/shτρέξιμο /bin/bash, τότε μάλλον δεν θα παρατηρήσετε.

Απαντήθηκε 02/06/2017 στις 20:14
πηγή χρήστη

ψήφοι
7

Μπορείτε επίσης να χρησιμοποιήσετε τους φορείς βαρεία ( `), παρόμοια με Perl:

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

Handy αν χρειάζεστε κάτι απλό.

Ποια μέθοδο που θέλετε να χρησιμοποιήσετε εξαρτάται από το τι ακριβώς προσπαθείτε να πετύχετε? ελέγξτε τα έγγραφα για περισσότερες λεπτομέρειες σχετικά με τις διάφορες μεθόδους.

Απαντήθηκε 05/08/2008 στις 14:57
πηγή χρήστη

ψήφοι
5

Μην ξεχνάτε την spawnεντολή για να δημιουργήσετε μια διαδικασία φόντο για να εκτελέσει την καθορισμένη εντολή. Μπορείτε ακόμη και να περιμένετε για την ολοκλήρωσή της με τη χρήση της Processκατηγορίας και το επέστρεψε 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

Το έγγραφο αναφέρει: Αυτή η μέθοδος είναι παρόμοια με #system, αλλά δεν περιμένει την εντολή μέχρι το τέλος.

Απαντήθηκε 04/11/2015 στις 15:04
πηγή χρήστη

ψήφοι
5

Χρησιμοποιώντας τις απαντήσεις εδώ και συνδέονται σε απάντηση Mihai του, έβαλα μαζί μια συνάρτηση που ικανοποιεί αυτές τις απαιτήσεις:

  1. Τακτοποιημένα συλλαμβάνει STDOUT και STDERR έτσι ώστε να μην «διαρροή» όταν το σενάριό μου τρέχει από την κονσόλα.
  2. Επιτρέπει επιχειρήματα που πρέπει να περάσει στο κέλυφος ως μια σειρά, οπότε δεν υπάρχει λόγος να ανησυχείτε για τη διαφυγή.
  3. Κρύβει μέσα του την κατάσταση εξόδου της εντολής, ώστε να είναι σαφές πότε έχει συμβεί κάποιο σφάλμα.

Ως μπόνους, αυτό θα επιστρέψει επίσης STDOUT σε περιπτώσεις όπου οι έξοδοι εντολή κελύφους με επιτυχία (0) και βάζει τα πάντα για STDOUT. Με τον τρόπο αυτό, διαφέρει από system, η οποία απλώς επιστρέφει trueσε τέτοιες περιπτώσεις.

Κωδικός εξής. Η ειδική λειτουργία είναι 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"
Απαντήθηκε 21/02/2012 στις 00:36
πηγή χρήστη

ψήφοι
5

Μπορούμε να το επιτύχουμε με πολλούς τρόπους.

Χρησιμοποιώντας Kernel#exec, τίποτα αφού εκτελείται αυτή η εντολή:

exec('ls ~')

Χρησιμοποιώντας backticks or %x

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

Χρησιμοποιώντας Kernel#systemτην εντολή, επιστρέφει trueσε περίπτωση επιτυχίας, falseαν ηττηθεί και επιστροφές nilεφόσον η εκτέλεση εντολών αποτύχει:

system('ls ~')
=> true
Απαντήθηκε 19/02/2012 στις 19:07
πηγή χρήστη

ψήφοι
4

ευκολότερος τρόπος είναι, για παράδειγμα:

reboot = `init 6`
puts reboot
Απαντήθηκε 30/03/2017 στις 18:13
πηγή χρήστη

ψήφοι
3
  • βαρεία μέθοδο `είναι το πιο εύκολο να καλέσετε εντολές του κελύφους από ρουμπίνι. Επιστρέφει το αποτέλεσμα της εντολής κελύφους.

     url_request = 'http://google.com'
     result_of_shell_command = `curl #{url_request}`
    
Απαντήθηκε 16/02/2017 στις 09:58
πηγή χρήστη

ψήφοι
3

Αν έχετε μια πιο περίπλοκη υπόθεση από την συνηθισμένη περίπτωση (που δεν μπορεί να αντιμετωπιστεί με ``) τότε δείτε Kernel.spawn() εδώ . Αυτή φαίνεται να είναι η πιο γενική / πλήρεις δυνατότητες που παρέχονται από απόθεμα Ruby να εκτελέσει τις εξωτερικές εντολές.

Για παράδειγμα, μπορείτε να το χρησιμοποιήσετε για να:

  • δημιουργήσετε ομάδες διαδικασία (Windows)
  • ανακατεύθυνση σε, έξω, λάθος στα αρχεία / η μία την άλλη.
  • σύνολο env μεταπωλητές, umask
  • αλλάξτε dir πριν από την εκτέλεση εντολών
  • Όρια σύνολο των πόρων για CPU / δεδομένων / ...
  • Κάνετε ό, τι μπορεί να γίνει με άλλες επιλογές σε άλλες απαντήσεις, αλλά με περισσότερες κωδικό.

Επίσημη τεκμηρίωση ρουμπίνι έχει αρκετά καλά παραδείγματα.

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/12/2015 στις 14:57
πηγή χρήστη

ψήφοι
1

Λαμβάνοντας υπόψη μια εντολή π.χ. attrib

require 'open3'

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

Έχω διαπιστώσει ότι ενώ η μέθοδος αυτή δεν είναι τόσο αξέχαστη, όπως π.χ. σύστημα ( «thecommand») ή thecommand σε βαρεία, ένα καλό πράγμα για τη μέθοδο αυτή σε σύγκριση με άλλες μεθόδους .. είναι π.χ. βαρεία δεν φαίνεται να επιτρέψτε μου να «puts «η εντολή τρέχω / κατάστημα η εντολή που θέλω να τρέξει σε μια μεταβλητή, και το σύστημα (“thecommand”) δεν φαίνεται να επιτρέψτε μου να πάρει το αποτέλεσμα. Ότι η παρούσα μέθοδος επιτρέπει να κάνουμε και τα δύο από αυτά τα πράγματα, και αυτό μου επιτρέπει stdin πρόσβαση, stdout και stderr ανεξάρτητα.

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

Απαντήθηκε 19/12/2017 στις 05:54
πηγή χρήστη

ψήφοι
0

Δεν είναι πραγματικά μια απάντηση, αλλά ίσως κάποιος θα βρείτε αυτό το χρήσιμο, και της σχετικά με αυτό.

Όταν χρησιμοποιείτε ΤΚ GUI για Windows και u πρέπει να καλέσετε εντολές του κελύφους από rubyw, u θα έχουν πάντα ένα ενοχλητικό παράθυρο cmd βρεθώ για λιγότερο από ένα δευτερόλεπτο.

Για να αποφύγετε αυτό το u μπορεί να χρησιμοποιήσει

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

ή

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

Και οι δύο θα αποθηκεύσει εξόδου ipconfig είναι μέσα «log.txt», αλλά χωρίς παράθυρα θα καταλήξει.

U θα πρέπει να require 'win32ole'μέσα στο σενάριό σας.

system(), exec()Και spawn()όλα θα εμφανιστεί εκείνο το ενοχλητικό παράθυρο όταν χρησιμοποιούν ΤΚ και rubyw.

Απαντήθηκε 05/07/2018 στις 12:55
πηγή χρήστη

ψήφοι
-1

Εδώ είναι ένα δροσερό αυτό που μπορώ να χρησιμοποιήσω σε ένα ρουμπίνι σενάριο για OS X (ώστε να μπορώ να ξεκινήσετε ένα σενάριο και να πάρετε μια ενημέρωση, ακόμη και μετά την εναλλαγή μακριά από το παράθυρο):

cmd = %Q|osascript -e 'display notification "Server was reset" with title "Posted Update"'|
system ( cmd )
Απαντήθηκε 14/10/2014 στις 21:12
πηγή χρήστη

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