Wie verwende ich Ruby für Shell-Skripte?


165

Ich habe einige einfache Shell-Scripting-Aufgaben, die ich ausführen möchte

Beispiel: Auswählen einer Datei im Arbeitsverzeichnis aus einer Liste der Dateien, die einem regulären Ausdruck entsprechen.

Ich weiß, dass ich so etwas mit Standard-Bash und Grep machen kann, aber ich wäre schön, wenn ich schnelle Skripte hacken könnte, die unter Windows und Linux funktionieren, ohne dass ich mir einen Haufen Befehlszeilenprogramme und Flags usw. merken muss.

Ich habe versucht, dies in Gang zu bringen, war jedoch verwirrt darüber, wo ich Informationen wie einen Verweis auf das aktuelle Verzeichnis erhalten sollte

Die Frage ist also, welche Teile der Ruby-Bibliotheken ich wissen muss, um Ruby-Shell-Skripte zu schreiben.


2
Wahrscheinlich keine gute Antwort, aber Practical Ruby für die Systemadministration ist eine gute Referenz. amazon.com/Practical-System-Administration-Experts-Source/dp/…
Exiquio

Antworten:


147

Standardmäßig haben Sie bereits Zugriff auf Dir und File , die für sich genommen sehr nützlich sind.

Dir['*.rb'] #basic globs
Dir['**/*.rb'] #** == any depth of directory, including current dir.
#=> array of relative names

File.expand_path('~/file.txt') #=> "/User/mat/file.txt"
File.dirname('dir/file.txt') #=> 'dir'
File.basename('dir/file.txt') #=> 'file.txt'
File.join('a', 'bunch', 'of', 'strings') #=> 'a/bunch/of/strings'

__FILE__ #=> the name of the current file

Ebenfalls nützlich von der stdlib ist FileUtils

require 'fileutils' #I know, no underscore is not ruby-like
include FileUtils
# Gives you access (without prepending by 'FileUtils.') to
cd(dir, options)
cd(dir, options) {|dir| .... }
pwd()
mkdir(dir, options)
mkdir(list, options)
mkdir_p(dir, options)
mkdir_p(list, options)
rmdir(dir, options)
rmdir(list, options)
ln(old, new, options)
ln(list, destdir, options)
ln_s(old, new, options)
ln_s(list, destdir, options)
ln_sf(src, dest, options)
cp(src, dest, options)
cp(list, dir, options)
cp_r(src, dest, options)
cp_r(list, dir, options)
mv(src, dest, options)
mv(list, dir, options)
rm(list, options)
rm_r(list, options)
rm_rf(list, options)
install(src, dest, mode = <src's>, options)
chmod(mode, list, options)
chmod_R(mode, list, options)
chown(user, group, list, options)
chown_R(user, group, list, options)
touch(list, options)

Welches ist ziemlich schön


110

Wie die anderen bereits gesagt haben, sollte Ihre erste Zeile sein

#!/usr/bin/env ruby

Und Sie müssen es auch ausführbar machen: (in der Shell)

chmod +x test.rb

Dann folgt der Ruby-Code. Wenn Sie eine Datei öffnen

File.open("file", "r") do |io|
    # do something with io
end

Die Datei wird in dem aktuellen Verzeichnis geöffnet, mit dem Sie pwdin der Shell arbeiten würden.

Der Pfad zu Ihrem Skript ist ebenfalls einfach zu finden. Mit erhalten $0Sie das erste Argument der Shell, das der relative Pfad zu Ihrem Skript ist. Der absolute Pfad kann folgendermaßen bestimmt werden:

#!/usr/bin/env ruby
require 'pathname'
p Pathname.new($0).realpath()

Für Dateisystemoperationen verwende ich fast immer den Pfadnamen. Dies ist ein Wrapper für viele andere Klassen, die sich auf das Dateisystem beziehen. Auch nützlich: Dir, File ...


66

In den anderen Antworten fehlt Folgendes: Die Befehlszeilenparameter werden über das ARGV-Array (global) für Ihr Ruby-Shell-Skript verfügbar gemacht.

Wenn Sie also ein Skript namens my_shell_script hatten:

#!/usr/bin/env ruby
puts "I was passed: "
ARGV.each do |value|
  puts value
end

... machen es ausführbar (wie andere erwähnt haben):

chmod u+x my_shell_script

Und nenne es so:

> ./my_shell_script one two three four five

Sie würden dies bekommen:

I was passed: 
one
two
three
four
five

Die Argumente funktionieren gut mit der Dateinamenerweiterung:

./my_shell_script *

I was passed: 
a_file_in_the_current_directory
another_file    
my_shell_script
the_last_file

Das meiste davon funktioniert nur unter UNIX (Linux, Mac OS X), aber Sie können ähnliche (wenn auch weniger bequeme) Dinge in Windows tun.


32

Hier gibt es viele gute Ratschläge, deshalb wollte ich noch ein bisschen mehr hinzufügen.

  1. Mit Backticks (oder Back-Ticks) können Sie einige Skripte viel einfacher erstellen. Erwägen

    puts `find . | grep -i lib`
  2. Wenn Sie Probleme beim Abrufen der Ausgabe von Backticks haben, wird das Zeug auf Standardfehler anstatt auf Standardausgang umgestellt. Verwenden Sie diesen Rat

    out = `git status 2>&1`
  3. Backticks führen eine String-Interpolation durch:

    blah = 'lib'
    `touch #{blah}`
    
  4. Sie können auch in Ruby pfeifen . Es ist ein Link zu meinem Blog, aber es verlinkt hierher zurück, also ist es okay :) Es gibt wahrscheinlich fortgeschrittenere Dinge zu diesem Thema.

  5. Wie andere Leute bemerkt haben, gibt es Rush, wenn Sie es ernst meinen wollen: nicht nur als Shell-Ersatz (was für mich etwas zu verrückt ist), sondern auch als Bibliothek für Ihre Verwendung in Shell-Skripten und -Programmen.


Verwenden Sie auf einem Mac Applescript in Ruby, um mehr Leistung zu erhalten. Hier ist mein shell_hereSkript:

#!/usr/bin/env ruby
`env | pbcopy` 
cmd =  %Q@tell app "Terminal" to do script "$(paste_env)"@
puts cmd

`osascript -e "${cmd}"`

Ich musste nur den Code 4 weitere Leerzeichen einrücken, damit sie formatiert werden konnten. Ich habe auch die Backticks zurückgesetzt, aber ich kenne Ruby überhaupt nicht sehr gut. Sie sollten also überprüfen, ob es das ist, was Sie beabsichtigt haben.
Bill the Lizard

@ Bill the Lizard, ja, das war der 'Trick', den ich brauchte: die doppelten Einrückungen. DANKE FÜR DIE HILFE.
Dan Rosenstark


21

Holen Sie sich eine Kopie von Everyday Scripting with Ruby . Es enthält viele nützliche Tipps, wie Sie die Dinge tun können, die Sie tun möchten.


1
Gutes Buch, ich lese es gerade: Es fühlt sich an wie eine Zen-Code-Reise. Und wenn Sie TDD nicht kennen, lernen Sie die Grundlagen von TDD auf dem ganzen Weg.
Sébastien RoccaSerra

Ich denke, das Buch hat einige gute Informationen, aber für erfahrene Programmierer zu viel Aufwand.
Das D fusionierte am

12

Dies kann auch hilfreich sein: http://rush.heroku.com/

Ich habe es nicht viel benutzt, sieht aber ziemlich cool aus

Von der Website:

Rush ist ein Ersatz für die Unix-Shell (bash, zsh usw.), die reine Ruby-Syntax verwendet. Durchsuchen Sie Dateien, suchen und beenden Sie Prozesse, kopieren Sie Dateien - alles, was Sie in der Shell tun, jetzt in Ruby


2
Ansturm: nein. Warum? groups.google.com/group/ruby-shell/browse_thread/thread/… Es ist großartig, aber es sitzt niemand am Steuer.
Dan Rosenstark

12

Nehmen wir an, Sie schreiben Ihr script.rbSkript. stellen:

#!/usr/bin/env ruby

als erste Zeile und mache a chmod +x script.rb


7

Wenn Sie komplexere Ruby-Skripte schreiben möchten, können diese Tools hilfreich sein:

Beispielsweise:

  • thor (ein Skript-Framework)

  • gli (git like interface)

  • Methadon (zum Erstellen einfacher Werkzeuge)

Sie bieten Ihnen einen schnellen Einstieg in das Schreiben eigener Skripte, insbesondere der 'Befehlszeilen-App'.


4

"Wie schreibe ich Ruby" geht etwas über den Rahmen von SO hinaus.

Um diese Ruby-Skripte in ausführbare Skripte umzuwandeln, setzen Sie dies als erste Zeile Ihres Ruby-Skripts:

#!/path/to/ruby

Dann machen Sie die Datei ausführbar:

chmod a+x myscript.rb

und los gehts.


4

Platzieren Sie dies am Anfang Ihrer script.rb

#!/usr/bin/env ruby

Markieren Sie es dann als ausführbar:

chmod +x script.rb

4

Die obigen Antworten sind interessant und sehr hilfreich, wenn Ruby als Shell-Skript verwendet wird. Für mich verwende ich Ruby nicht als meine tägliche Sprache und ich bevorzuge Ruby nur als Flusskontrolle und verwende immer noch Bash, um die Aufgaben zu erledigen.

Einige Hilfsfunktionen können zum Testen des Ausführungsergebnisses verwendet werden

#!/usr/bin/env ruby
module ShellHelper
  def test(command)
    `#{command} 2> /dev/null`
    $?.success?
  end

  def execute(command, raise_on_error = true)
    result = `#{command}`
    raise "execute command failed\n" if (not $?.success?) and raise_on_error
    return $?.success?
  end

  def print_exit(message)
    print "#{message}\n"
    exit
  end

  module_function :execute, :print_exit, :test
end

Mit dem Helfer könnte das Ruby-Skript ähnlich sein:

#!/usr/bin/env ruby
require './shell_helper'
include ShellHelper

print_exit "config already exists" if test "ls config"

things.each do |thing|
  next if not test "ls #{thing}/config"
  execute "cp -fr #{thing}/config_template config/#{thing}"
end

3

Die Antwort per Webmat ist perfekt. Ich möchte Sie nur auf einen Zusatz hinweisen. Wenn Sie viel mit Befehlszeilenparametern für Ihre Skripte zu tun haben, sollten Sie optparse verwenden . Es ist einfach und hilft Ihnen enorm.


3

In Ruby __FILE__gibt Ihnen die Konstante immer den Pfad des Skripts an, das Sie ausführen.

Unter Linux /usr/bin/envist dein Freund:

#! /usr/bin/env ruby
# Extension of this script does not matter as long
# as it is executable (chmod +x)
puts File.expand_path(__FILE__)

Unter Windows hängt es davon ab, ob .rb-Dateien mit Ruby verknüpft sind oder nicht. Wenn sie sind:

# This script filename must end with .rb
puts File.expand_path(__FILE__)

Wenn dies nicht der Fall ist, müssen Sie Ruby explizit aufrufen. Ich verwende eine CMD-Zwischendatei:

my_script.cmd:

@ruby %~dp0\my_script.rb

my_script.rb:

puts File.expand_path(__FILE__)
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.