Como uso o Ruby para scripts de shell?

165

Eu tenho algumas tarefas simples de script de shell que eu quero fazer

Por exemplo: Selecionando um arquivo no diretório ativo de uma lista dos arquivos que correspondem a alguma expressão regular.

Eu sei que posso fazer esse tipo de coisa usando bash e grep padrão, mas seria bom poder hackear scripts rápidos que funcionem no Windows e Linux sem que eu tenha que memorizar uma pilha de programas de linha de comando e sinalizadores etc.

Tentei fazer isso, mas acabei ficando confuso sobre onde deveria obter informações, como uma referência ao diretório atual.

Portanto, a questão é quais partes das bibliotecas Ruby eu preciso saber para escrever scripts shell ruby?

Willbill
fonte
3
Provavelmente não é uma boa resposta, mas o Ruby Prático para Administração de Sistemas é uma ótima referência. amazon.com/Practical-System-Administration-Experts-Source/dp/…
exiquio

Respostas:

148

Por padrão, você já tem acesso ao Dir e ao arquivo , que são bastante úteis por si só.

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

Também útil no stdlib é o 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)

O que é bem legal

webmat
fonte
110

Como os outros já disseram, sua primeira linha deve ser

#!/usr/bin/env ruby

E você também precisa torná-lo executável: (no shell)

chmod +x test.rb

Depois segue o código ruby. Se você abrir um arquivo

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

o arquivo é aberto no diretório atual que você obteria pwdno shell.

O caminho para o seu script também é simples de obter. Com $0você, obtém o primeiro argumento do shell, que é o caminho relativo para o seu script. O caminho absoluto pode ser determinado assim:

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

Para operações do sistema de arquivos, quase sempre uso o Pathname. Este é um invólucro para muitas das outras classes relacionadas ao sistema de arquivos. Também é útil: Dir, File ...

Georg Schölly
fonte
66

Aqui está algo importante que está faltando nas outras respostas: os parâmetros da linha de comando são expostos ao seu script de shell Ruby por meio da matriz ARGV (global).

Portanto, se você tivesse um script chamado my_shell_script:

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

... torná-lo executável (como outros já mencionaram):

chmod u+x my_shell_script

E chame assim:

> ./my_shell_script one two three four five

Você obteria isso:

I was passed: 
one
two
three
four
five

Os argumentos funcionam bem com a expansão do nome do arquivo:

./my_shell_script *

I was passed: 
a_file_in_the_current_directory
another_file    
my_shell_script
the_last_file

A maior parte disso funciona apenas no UNIX (Linux, Mac OS X), mas você pode fazer coisas semelhantes (embora menos convenientes) no Windows.

Craig Walker
fonte
32

Há muitos bons conselhos aqui, então eu queria adicionar um pouquinho mais.

  1. Os backticks (ou back-ticks) permitem fazer algumas coisas de script muito mais facilmente. Considerar

    puts `find . | grep -i lib`
  2. Se você tiver problemas para obter a saída dos backticks, o problema será o erro padrão, em vez de sair do padrão. Use este conselho

    out = `git status 2>&1`
  3. Os backticks fazem interpolação de string:

    blah = 'lib'
    `touch #{blah}`
  4. Você também pode entrar no Ruby . É um link para o meu blog, mas tem um link aqui, então está tudo bem :) Provavelmente existem coisas mais avançadas por aí sobre este tópico.

  5. Como outras pessoas notaram, se você quer levar a sério, existe o Rush: não apenas como um substituto do shell (o que é um pouco doido demais para mim), mas também como uma biblioteca para seu uso em scripts e programas do shell.


No Mac, use Applescript dentro do Ruby para obter mais poder. Aqui está o meu 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
fonte
Eu apenas tive que recuar o código mais 4 espaços para que eles fossem formatados. Também retiro os backticks, mas não conheço muito bem o Ruby, então você deve verificar se é o que pretendia.
Bill o Lagarto
@ Bill the Lizard, sim, esse era o 'truque' que eu estava precisando: os dois travessões. OBRIGADO PELA AJUDA.
Dan Rosenstark 6/03/10
1
Acho que o Rush está morto: groups.google.com/group/ruby-shell/browse_thread/thread/…
Dan Rosenstark
22

Compre uma cópia do Everyday Scripting with Ruby . Tem muitas dicas úteis sobre como fazer os tipos de coisas que você deseja fazer.

Aaron Hinni
fonte
2
Bom livro, estou lendo agora: parece uma jornada de código zen. E se você não conhece o TDD, aprenderá o básico do TDD por todo o caminho.
Sébastien RoccaSerra
Eu acho que o livro tem algumas informações boas, mas muito caras para programadores experientes.
OD mesclou
12

Isso também pode ser útil: http://rush.heroku.com/

Eu não usei muito, mas parece bem legal

Do site:

rush é um substituto para o shell unix (bash, zsh, etc) que usa a sintaxe pura do Ruby. Navegue através de arquivos, encontre e mate processos, copie arquivos - tudo o que você faz no shell, agora em Ruby

craigp
fonte
2
Rush: não. Por quê? groups.google.com/group/ruby-shell/browse_thread/thread/… É ótimo, mas não há ninguém no volante.
Dan Rosenstark
12

digamos que você escreva seu script.rbscript. colocar:

#!/usr/bin/env ruby

como a primeira linha e faça um chmod +x script.rb

Vasil
fonte
7

Quando você deseja escrever scripts ruby ​​mais complexos, essas ferramentas podem ajudar:

Por exemplo:

  • thor (uma estrutura de script)

  • gli (interface semelhante ao git)

  • metadona (para criar ferramentas simples)

Eles dão a você um começo rápido para escrever seus próprios scripts, especialmente o 'aplicativo de linha de comando'.

Bohr
fonte
5

A resposta acima é interessante e muito útil ao usar Ruby como shell script. Para mim, eu não uso Ruby como minha linguagem diária e prefiro usar ruby ​​apenas como controle de fluxo e ainda usar o bash para executar as tarefas.

Alguma função auxiliar pode ser usada para testar o resultado da execução

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

Com o helper, o script ruby ​​pode ser semelhante ao 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
fonte
Cara, isso é ótimo, obrigado!
Victor Martins
4

"Como eu escrevo ruby" está um pouco além do escopo do SO.

Mas, para transformar esses scripts ruby ​​em scripts executáveis, coloque isso como a primeira linha do seu script ruby:

#!/path/to/ruby

Em seguida, torne o arquivo executável:

chmod a+x myscript.rb

e você vai embora.

Matthew Scharley
fonte
4

Coloque isso no início do seu script.rb

#!/usr/bin/env ruby

Em seguida, marque-o como executável:

chmod +x script.rb
Daniel Beardsley
fonte
3

A resposta do webmat é perfeita. Eu só quero te indicar uma adição. Se você precisar lidar muito com os parâmetros da linha de comando para seus scripts, use optparse . É simples e ajuda tremendamente.

awenkhh
fonte
3

Em ruby, a constante __FILE__sempre fornecerá o caminho do script que você está executando.

No Linux, /usr/bin/envé seu 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__)

No Windows, depende se os arquivos .rb estão ou não associados ao ruby. Se eles são:

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

Se não estiverem, você precisará chamar explicitamente o ruby, eu uso um arquivo .cmd intermediário:

my_script.cmd:

@ruby %~dp0\my_script.rb

my_script.rb:

puts File.expand_path(__FILE__)
bltxd
fonte