Làm cách nào để sử dụng Ruby cho kịch bản shell?


165

Tôi có một số tác vụ kịch bản shell đơn giản mà tôi muốn làm

Ví dụ: Chọn một tệp trong thư mục làm việc từ danh sách các tệp khớp với một số biểu thức chính quy.

Tôi biết rằng tôi có thể thực hiện việc này bằng cách sử dụng bash và grep tiêu chuẩn nhưng tôi sẽ rất vui khi có thể hack các tập lệnh nhanh sẽ hoạt động trong windows và linux mà không cần phải ghi nhớ một đống chương trình dòng lệnh và cờ, v.v.

Tôi đã cố gắng để thực hiện điều này nhưng cuối cùng lại bị nhầm lẫn về nơi tôi sẽ nhận được thông tin như tham chiếu đến thư mục hiện tại

Vì vậy, câu hỏi là những phần nào của thư viện Ruby tôi cần biết để viết các tập lệnh shell ruby?


2
Có lẽ không phải là một câu trả lời hay, nhưng Thực tế Ruby cho Quản trị hệ thống là một tài liệu tham khảo tuyệt vời. amazon.com/Practical-System-Adftime-Experts-Source/dp/
Kẻ

Câu trả lời:


147

Theo mặc định, bạn đã có quyền truy cập vào DirFile , chúng khá hữu ích.

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

Cũng hữu ích từ stdlib là 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)

Cái nào cũng đẹp


110

Như những người khác đã nói, dòng đầu tiên của bạn phải là

#!/usr/bin/env ruby

Và bạn cũng phải làm cho nó có thể thực thi được: (trong shell)

chmod +x test.rb

Sau đó làm theo mã ruby. Nếu bạn mở một tập tin

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

tập tin được mở trong thư mục hiện tại mà bạn nhận được pwdtrong shell.

Đường dẫn đến kịch bản của bạn cũng đơn giản để có được. Với $0bạn có được đối số đầu tiên của shell, đó là đường dẫn tương đối đến tập lệnh của bạn. Đường dẫn tuyệt đối có thể được xác định như thế:

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

Đối với các hoạt động hệ thống tập tin, tôi hầu như luôn luôn sử dụng Pathname. Đây là một trình bao bọc cho nhiều lớp liên quan đến hệ thống tệp khác. Cũng hữu ích: Dir, File ...


66

Đây là một điều quan trọng bị thiếu trong các câu trả lời khác: các tham số dòng lệnh được hiển thị với tập lệnh shell Ruby của bạn thông qua mảng ARGV (toàn cầu).

Vì vậy, nếu bạn có một tập lệnh gọi là my_shell_script:

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

... làm cho nó có thể thực thi được (như những người khác đã đề cập):

chmod u+x my_shell_script

Và gọi nó như vậy:

> ./my_shell_script one two three four five

Bạn sẽ nhận được điều này:

I was passed: 
one
two
three
four
five

Các đối số hoạt động độc đáo với mở rộng tên tệp:

./my_shell_script *

I was passed: 
a_file_in_the_current_directory
another_file    
my_shell_script
the_last_file

Hầu hết những thứ này chỉ hoạt động trên UNIX (Linux, Mac OS X), nhưng bạn có thể làm những việc tương tự (mặc dù ít thuận tiện hơn) trong Windows.


32

Có rất nhiều lời khuyên tốt ở đây, vì vậy tôi muốn thêm một chút nữa.

  1. Backticks (hoặc back-ticks) cho phép bạn thực hiện một số nội dung kịch bản dễ dàng hơn nhiều. Xem xét

    puts `find . | grep -i lib`
  2. Nếu bạn gặp vấn đề với việc nhận đầu ra của backticks, công cụ sẽ chuyển sang lỗi tiêu chuẩn thay vì tiêu chuẩn. Sử dụng lời khuyên này

    out = `git status 2>&1`
  3. Backticks thực hiện nội suy chuỗi:

    blah = 'lib'
    `touch #{blah}`
  4. Bạn cũng có thể đặt ống bên trong Ruby . Đó là một liên kết đến blog của tôi, nhưng nó liên kết trở lại ở đây vì vậy nó ổn :) Có lẽ có nhiều thứ nâng cao hơn về chủ đề này.

  5. Như những người khác đã lưu ý, nếu bạn muốn nghiêm túc thì có Rush: không chỉ là một sự thay thế vỏ (điều này hơi quá đối với tôi) mà còn là một thư viện để bạn sử dụng trong các kịch bản và chương trình shell.


Trên Mac, Sử dụng Applescript bên trong Ruby để có thêm sức mạnh. Đây là shell_herekịch bản của tôi :

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

`osascript -e "${cmd}"`

Tôi chỉ cần thụt mã thêm 4 khoảng trắng để chúng được định dạng. Tôi cũng đặt backticks trở lại, nhưng tôi hoàn toàn không biết Ruby, vì vậy bạn sẽ muốn kiểm tra để đảm bảo đó là những gì bạn dự định.
Hóa đơn thằn lằn

@Bill the Lizard, yeah, đó là 'mẹo' tôi cần: các vết lõm kép. CẢM ƠN ĐÃ GIÚP ĐỠ.
Dan Rosenstark


21

Hãy lấy cho mình một bản sao của Script hàng ngày với Ruby . Nó có rất nhiều lời khuyên hữu ích về cách thực hiện các loại việc bạn muốn làm.


1
Cuốn sách hay, tôi đang đọc nó ngay bây giờ: cảm giác như một hành trình mã zen. Và nếu bạn không biết TDD, bạn sẽ học được những điều cơ bản của TDD.
Sébastien RoccaSerra

Tôi nghĩ rằng cuốn sách có một số thông tin tốt nhưng nhiều chi phí cho các lập trình viên có kinh nghiệm.
The D Sáp nhập

12

Điều này cũng có thể hữu ích: http://rush.heroku.com/

Tôi đã không sử dụng nó nhiều, nhưng trông khá tuyệt

Từ trang web:

rush là một thay thế cho shell unix (bash, zsh, v.v.) sử dụng cú pháp Ruby thuần túy. Grep thông qua các tệp, tìm và diệt các tiến trình, sao chép các tệp - mọi thứ bạn làm trong trình bao, bây giờ trong Ruby


2
Vội vàng: không. Tại sao? Groups.google.com/group/ruby-shell/browse_thread/thread/ Khăn Thật tuyệt vời nhưng không có ai ở tay lái.
Dan Rosenstark

12

giả sử bạn viết script.rbkịch bản của bạn đặt:

#!/usr/bin/env ruby

là dòng đầu tiên và làm một chmod +x script.rb


7

Khi bạn muốn viết các tập lệnh ruby ​​phức tạp hơn, các công cụ này có thể giúp:

Ví dụ:

  • thor (một khung kịch bản)

  • gli (giao diện giống như git)

  • methadone (để tạo các công cụ đơn giản)

Chúng cung cấp cho bạn một khởi đầu nhanh chóng để viết các tập lệnh của riêng bạn, đặc biệt là 'ứng dụng dòng lệnh'.


4

"Làm thế nào để tôi viết ruby" là một chút vượt quá phạm vi của SO.

Nhưng để biến các tập lệnh ruby ​​này thành tập lệnh thực thi, hãy đặt đây là dòng đầu tiên của tập lệnh ruby ​​của bạn:

#!/path/to/ruby

Sau đó làm cho tập tin thực thi:

chmod a+x myscript.rb

và đi em đi.


4

Đặt cái này vào đầu script.rb của bạn

#!/usr/bin/env ruby

Sau đó đánh dấu nó là thực thi:

chmod +x script.rb

4

Câu trả lời trên rất thú vị và rất hữu ích khi sử dụng Ruby làm kịch bản shell. Đối với tôi, tôi không sử dụng Ruby làm ngôn ngữ hàng ngày và tôi chỉ thích sử dụng ruby ​​làm kiểm soát dòng chảy và vẫn sử dụng bash để thực hiện các tác vụ.

Một số chức năng của trình trợ giúp có thể được sử dụng để kiểm tra kết quả thực hiệ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

Với người trợ giúp, kịch bản ruby ​​có thể giống nhau:

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

Câu trả lời của webmat là hoàn hảo. Tôi chỉ muốn chỉ cho bạn một bổ sung. Nếu bạn phải xử lý nhiều thông số dòng lệnh cho tập lệnh của mình, bạn nên sử dụng optparse . Nó rất đơn giản và giúp bạn rất nhiều.


3

Trong ruby, hằng số __FILE__sẽ luôn cung cấp cho bạn đường dẫn của tập lệnh bạn đang chạy.

Trên Linux, /usr/bin/envlà bạn của bạn:

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

Trên Windows, nó phụ thuộc vào việc các tệp .rb có được liên kết với ruby ​​hay không. Nếu họ là:

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

Nếu chúng không phải, bạn phải gọi ruby ​​một cách rõ ràng, tôi sử dụng tệp .cmd trung gian:

my_script.cmd:

@ruby %~dp0\my_script.rb

my_script.rb:

puts File.expand_path(__FILE__)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.