Comment utiliser Ruby pour les scripts shell?

165

J'ai quelques tâches de script shell simples que je veux faire

Par exemple: sélectionner un fichier dans le répertoire de travail à partir d'une liste de fichiers correspondant à une expression régulière.

Je sais que je peux faire ce genre de chose en utilisant bash et grep standard, mais je serais bien de pouvoir pirater des scripts rapides qui fonctionneront sous Windows et Linux sans que je doive mémoriser un tas de programmes de ligne de commande et d'indicateurs, etc.

J'ai essayé de faire avancer les choses mais j'ai fini par me demander où je devrais obtenir des informations telles qu'une référence au répertoire actuel

La question est donc de savoir quelles parties des bibliothèques Ruby dois-je connaître pour écrire des scripts shell ruby?

Willbill
la source
3
Probablement pas une bonne réponse, mais Practical Ruby for System Administration est une excellente référence. amazon.com/Practical-System-Administration-Experts-Source/dp/…
exiquio

Réponses:

148

Par défaut, vous avez déjà accès à Dir et File , qui sont assez utiles en eux-mêmes.

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

FileUtils est également utile à partir du stdlib

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)

Ce qui est plutôt sympa

webmat
la source
110

Comme les autres l'ont déjà dit, votre première ligne devrait être

#!/usr/bin/env ruby

Et vous devez également le rendre exécutable: (dans le shell)

chmod +x test.rb

Puis suit le code ruby. Si vous ouvrez un fichier

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

le fichier est ouvert dans le répertoire actuel que vous obtiendrez pwddans le shell.

Le chemin d'accès à votre script est également simple à obtenir. Avec $0vous obtenez le premier argument du shell, qui est le chemin relatif de votre script. Le chemin absolu peut être déterminé comme ça:

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

Pour les opérations du système de fichiers, j'utilise presque toujours Pathname. Il s'agit d'un wrapper pour de nombreuses autres classes liées au système de fichiers. Aussi utile: Dir, File ...

Georg Schölly
la source
66

Voici quelque chose d'important qui manque dans les autres réponses: les paramètres de ligne de commande sont exposés à votre script shell Ruby via le tableau ARGV (global).

Donc, si vous aviez un script appelé my_shell_script:

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

... rendez-le exécutable (comme d'autres l'ont mentionné):

chmod u+x my_shell_script

Et appelez-le comme ça:

> ./my_shell_script one two three four five

Vous obtiendrez ceci:

I was passed: 
one
two
three
four
five

Les arguments fonctionnent bien avec l'expansion des noms de fichiers:

./my_shell_script *

I was passed: 
a_file_in_the_current_directory
another_file    
my_shell_script
the_last_file

La plupart de cela ne fonctionne que sous UNIX (Linux, Mac OS X), mais vous pouvez faire des choses similaires (bien que moins pratiques) sous Windows.

Craig Walker
la source
32

Il y a beaucoup de bons conseils ici, alors je voulais en ajouter un peu plus.

  1. Les backticks (ou back-ticks) vous permettent de faire des scripts beaucoup plus facilement. Considérer

    puts `find . | grep -i lib`
  2. Si vous rencontrez des problèmes pour obtenir la sortie des backticks, le truc va à err standard au lieu de standard out. Utilisez ces conseils

    out = `git status 2>&1`
  3. Les backticks effectuent une interpolation de chaîne:

    blah = 'lib'
    `touch #{blah}`
  4. Vous pouvez également canaliser à l'intérieur de Ruby . C'est un lien vers mon blog, mais il renvoie ici, donc ça va :) Il y a probablement des choses plus avancées sur ce sujet.

  5. Comme d'autres l'ont noté, si vous voulez être sérieux, il y a Rush: pas seulement comme un remplacement de shell (ce qui est un peu trop loufoque pour moi) mais aussi comme une bibliothèque pour votre utilisation dans les scripts et programmes shell.


Sur Mac, utilisez Applescript dans Ruby pour plus de puissance. Voici mon shell_herescript:

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

`osascript -e "${cmd}"`
Dan Rosenstark
la source
Je devais juste indenter le code de 4 espaces supplémentaires pour qu'ils soient formatés. J'ai également remis les backticks, mais je ne connais pas très bien Ruby du tout, vous voudrez donc vérifier pour vous assurer que c'est ce que vous vouliez.
Bill the Lizard
@Bill the Lizard, oui, c'était le «truc» dont j'avais besoin: les doubles retraits. MERCI POUR L'AIDE.
Dan Rosenstark
1
Je pense que Rush est mort: groups.google.com/group/ruby-shell/browse_thread/thread/…
Dan Rosenstark
22

Allez vous procurer une copie de Everyday Scripting avec Ruby . Il contient de nombreux conseils utiles sur la façon de faire les types de choses que vous souhaitez faire.

Aaron Hinni
la source
2
Bon livre, je le lis en ce moment: ça ressemble à un voyage zen code. Et si vous ne connaissez pas TDD, vous apprendrez les bases de TDD en cours de route.
Sébastien RoccaSerra
Je pense que le livre contient de bonnes informations, mais trop de frais généraux pour les programmeurs expérimentés.
The D a fusionné le
12

Cela peut également être utile: http://rush.heroku.com/

Je ne l'ai pas beaucoup utilisé, mais ça a l'air plutôt cool

Depuis le site:

rush est un remplacement du shell unix (bash, zsh, etc.) qui utilise la pure syntaxe Ruby. Grep à travers des fichiers, rechercher et tuer des processus, copier des fichiers - tout ce que vous faites dans le shell, maintenant dans Ruby

craigp
la source
2
Rush: non. Pourquoi? groups.google.com/group/ruby-shell/browse_thread/thread/… C'est génial, mais il n'y a personne au volant.
Dan Rosenstark
12

disons que vous écrivez votre script.rbscript. mettre:

#!/usr/bin/env ruby

comme première ligne et faire un chmod +x script.rb

Vasil
la source
7

Lorsque vous souhaitez écrire des scripts ruby ​​plus complexes, ces outils peuvent vous aider:

Par exemple:

  • thor (un framework de script)

  • gli (git comme interface)

  • méthadone (pour créer des outils simples)

Ils vous donnent un démarrage rapide pour écrire vos propres scripts, en particulier «application en ligne de commande».

Bohr
la source
5

La réponse ci-dessus est intéressante et très utile lors de l'utilisation de Ruby comme script shell. Pour moi, je n'utilise pas Ruby comme langage quotidien et je préfère utiliser ruby ​​uniquement comme contrôle de flux et utiliser toujours bash pour faire les tâches.

Certaines fonctions d'assistance peuvent être utilisées pour tester le résultat de l'exécution

#!/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

Avec helper, le script ruby ​​pourrait être bash:

#!/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
Houcheng
la source
Mec, c'est super, merci!
Victor Martins le
4

"Comment écrire ruby" est un peu au-delà de la portée de SO.

Mais pour transformer ces scripts ruby ​​en scripts exécutables, mettez ceci comme première ligne de votre script ruby:

#!/path/to/ruby

Ensuite, rendez le fichier exécutable:

chmod a+x myscript.rb

et c'est parti.

Matthew Scharley
la source
4

Placez-le au début de votre script.rb

#!/usr/bin/env ruby

Puis marquez-le comme exécutable:

chmod +x script.rb
Daniel Beardsley
la source
3

La réponse par webmat est parfaite. Je veux juste vous signaler un ajout. Si vous devez beaucoup gérer les paramètres de ligne de commande pour vos scripts, vous devez utiliser optparse . C'est simple et vous aide énormément.

Awenkhh
la source
3

Dans ruby, la constante __FILE__vous donnera toujours le chemin du script que vous exécutez.

Sous Linux, /usr/bin/envvotre ami est-il:

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

Sous Windows, cela dépend si les fichiers .rb sont associés ou non à ruby. Si ils sont:

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

S'ils ne le sont pas, vous devez invoquer explicitement ruby ​​sur eux, j'utilise un fichier intermédiaire .cmd:

mon_script.cmd:

@ruby %~dp0\my_script.rb

mon_script.rb:

puts File.expand_path(__FILE__)
bltxd
la source