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

ψήφοι
862

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

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


20 απαντήσεις

ψήφοι
15

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

$ irb 
system "echo Hi"
Hi
=> true

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

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

ψήφοι
7

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

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

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

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

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

ψήφοι
150

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

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

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

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

ψήφοι
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
πηγή χρήστη

ψήφοι
23

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

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

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

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

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

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

ψήφοι
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
πηγή χρήστη

ψήφοι
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
πηγή χρήστη

ψήφοι
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
πηγή χρήστη

ψήφοι
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
πηγή χρήστη