¿Cómo uso Ruby para las secuencias de comandos de shell?

165

Tengo algunas tareas simples de scripting de shell que quiero hacer

Por ejemplo: Seleccionar un archivo en el directorio de trabajo de una lista de los archivos que coinciden con alguna expresión regular.

Sé que puedo hacer este tipo de cosas usando bash y grep estándar, pero sería bueno poder hackear scripts rápidos que funcionarán en Windows y Linux sin tener que memorizar un montón de programas de línea de comandos y banderas, etc.

Traté de poner esto en marcha pero terminé confundiéndome sobre dónde debería estar obteniendo información, como una referencia al directorio actual

Entonces, la pregunta es qué partes de las bibliotecas Ruby necesito saber para escribir scripts de shell Ruby.

Willbill
fuente
3
Probablemente no sea una buena respuesta, pero Practical Ruby for System Administration es una gran referencia. amazon.com/Practical-System-Administration-Experts-Source/dp/…
exiquio

Respuestas:

148

Por defecto, ya tienes acceso a Dir y File , que son bastante útiles por sí mismos.

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

También útil desde stdlib es 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)

Lo cual es bastante lindo

webmat
fuente
110

Como los otros ya han dicho, su primera línea debería ser

#!/usr/bin/env ruby

Y también tienes que hacerlo ejecutable: (en el shell)

chmod +x test.rb

Luego sigue el código ruby. Si abres un archivo

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

el archivo se abre en el directorio actual que obtendría pwden el shell.

El camino a su script también es fácil de obtener. Con $0usted obtiene el primer argumento del shell, que es la ruta relativa a su script. La ruta absoluta se puede determinar así:

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

Para las operaciones del sistema de archivos, casi siempre uso Pathname. Este es un contenedor para muchas de las otras clases relacionadas con el sistema de archivos. También útil: Dir, Archivo ...

Georg Schölly
fuente
66

Aquí hay algo importante que falta en las otras respuestas: los parámetros de la línea de comandos están expuestos a su script de shell Ruby a través de la matriz ARGV (global).

Entonces, si tenía un script llamado my_shell_script:

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

... hazlo ejecutable (como otros han mencionado):

chmod u+x my_shell_script

Y llámalo así:

> ./my_shell_script one two three four five

Obtendrías esto:

I was passed: 
one
two
three
four
five

Los argumentos funcionan bien con la expansión de nombre de archivo:

./my_shell_script *

I was passed: 
a_file_in_the_current_directory
another_file    
my_shell_script
the_last_file

La mayor parte de esto solo funciona en UNIX (Linux, Mac OS X), pero puede hacer cosas similares (aunque menos convenientes) en Windows.

Craig Walker
fuente
32

Hay muchos buenos consejos aquí, así que quería agregar un poquito más.

  1. Los backticks (o back-ticks) le permiten hacer algunas secuencias de comandos mucho más fácilmente. Considerar

    puts `find . | grep -i lib`
  2. Si tiene problemas para obtener la salida de los backticks, el material se equivocará en lugar de salir de forma estándar. Usa este consejo

    out = `git status 2>&1`
  3. Los backticks hacen interpolación de cadenas:

    blah = 'lib'
    `touch #{blah}`
  4. También puedes canalizar dentro de Ruby . Es un enlace a mi blog, pero está vinculado aquí, así que está bien :) Probablemente hay cosas más avanzadas sobre este tema.

  5. Como otras personas notaron, si quieres ponerte serio hay Rush: no solo como un reemplazo de shell (que es un poco estrafalario para mí) sino también como una biblioteca para tu uso en scripts y programas de shell.


En Mac, use Applescript dentro de Ruby para obtener más potencia. Aquí está mi shell_hereguión:

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

`osascript -e "${cmd}"`
Dan Rosenstark
fuente
Solo tuve que sangrar el código 4 espacios más para que se formateen. También puse los backticks de vuelta, pero no conozco a Ruby muy bien, por lo que querrá verificar para asegurarse de que sea lo que pretendía.
Bill the Lizard
@Bill the Lizard, sí, ese era el 'truco' que necesitaba: las dobles sangrías. GRACIAS POR LA AYUDA.
Dan Rosenstark
1
Creo que Rush está muerto: groups.google.com/group/ruby-shell/browse_thread/thread/…
Dan Rosenstark
22

Ve a buscar una copia de Everyday Scripting with Ruby . Tiene muchos consejos útiles sobre cómo hacer los tipos de cosas que desea hacer.

Aaron Hinni
fuente
2
Buen libro, lo estoy leyendo ahora: se siente como un viaje de código zen. Y si no conoce TDD, aprenderá los conceptos básicos de TDD todo el tiempo.
Sébastien RoccaSerra
Creo que el libro tiene buena información, pero demasiada sobrecarga para programadores experimentados.
The D Merged
12

Esto también podría ser útil: http://rush.heroku.com/

No lo he usado mucho, pero se ve muy bien

Desde el sitio:

rush es un reemplazo para el shell de Unix (bash, zsh, etc.) que usa la sintaxis pura de Ruby. Navegue por los archivos, encuentre y elimine procesos, copie archivos: todo lo que hace en el shell, ahora en Ruby

craigp
fuente
2
Rush: no. ¿Por qué? groups.google.com/group/ruby-shell/browse_thread/thread/… Es genial, pero no hay nadie al volante.
Dan Rosenstark
12

Digamos que escribes tu script.rbguión. poner:

#!/usr/bin/env ruby

como la primera línea y hacer un chmod +x script.rb

Vasil
fuente
7

Cuando desee escribir scripts ruby ​​más complejos, estas herramientas pueden ayudar:

Por ejemplo:

  • thor (un marco de secuencias de comandos)

  • gli (git como interfaz)

  • metadona (para crear herramientas simples)

Le dan un comienzo rápido para escribir sus propios scripts, especialmente 'aplicación de línea de comandos'.

Bohr
fuente
5

Las respuestas anteriores son interesantes y muy útiles cuando se utiliza Ruby como script de shell. Para mí, no uso Ruby como mi idioma diario y prefiero usar Ruby solo como control de flujo y todavía uso bash para hacer las tareas.

Se puede utilizar alguna función auxiliar para probar el resultado de ejecución

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

Con Helper, el script ruby ​​podría ser igual de 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
fuente
Hombre, esto es genial, gracias!
Victor Martins
4

"Cómo escribir rubí" está un poco más allá del alcance de SO.

Pero para convertir estos scripts de ruby ​​en scripts ejecutables, ponga esto como la primera línea de su script de ruby:

#!/path/to/ruby

Luego haga que el archivo sea ejecutable:

chmod a+x myscript.rb

y te vas.

Matthew Scharley
fuente
4

Coloque esto al comienzo de su script.rb

#!/usr/bin/env ruby

Luego márquelo como ejecutable:

chmod +x script.rb
Daniel Beardsley
fuente
3

La respuesta de webmat es perfecta. Solo quiero señalarle una adición. Si tiene que lidiar mucho con los parámetros de la línea de comandos para sus scripts, debe usar optparse . Es simple y te ayuda enormemente.

awenkhh
fuente
3

En ruby, la constante __FILE__siempre te dará la ruta del script que estás ejecutando.

En Linux, /usr/bin/enves tu amigo:

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

En Windows depende de si los archivos .rb están o no asociados con ruby. Si ellos estan:

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

Si no lo están, debe invocar explícitamente ruby ​​en ellos, utilizo un archivo intermedio .cmd:

my_script.cmd:

@ruby %~dp0\my_script.rb

my_script.rb:

puts File.expand_path(__FILE__)
bltxd
fuente