ฉันจะใช้ Ruby สำหรับการเขียนสคริปต์เชลล์ได้อย่างไร


165

ฉันมีงานการเขียนสคริปต์เชลล์แบบง่าย ๆ ที่ฉันต้องการทำ

ตัวอย่างเช่น: การเลือกไฟล์ในไดเรกทอรีการทำงานจากรายการไฟล์ที่ตรงกับนิพจน์ทั่วไป

ฉันรู้ว่าฉันสามารถทำสิ่งนี้โดยใช้มาตรฐานทุบตีและ grep แต่ฉันจะดีสามารถแฮ็คสคริปต์อย่างรวดเร็วที่จะทำงานใน windows และ linux โดยไม่ต้องจำกองโปรแกรมบรรทัดคำสั่งและธงเป็นต้น

ฉันพยายามทำสิ่งนี้ แต่จบลงด้วยความสับสนว่าฉันควรได้รับข้อมูลเช่นการอ้างอิงไปยังไดเรกทอรีปัจจุบัน

ดังนั้นคำถามคือส่วนใดของไลบรารี่ Ruby ที่ฉันต้องรู้ในการเขียนเชลล์สคริป


3
อาจไม่ใช่คำตอบที่ดี แต่ Ruby ที่เป็นประโยชน์สำหรับการบริหารระบบเป็นข้อมูลอ้างอิงที่ดี amazon.com/Practical-System-Administr-Experts-Source/dp/…
exiquio

คำตอบ:


148

โดยค่าเริ่มต้นคุณจะสามารถเข้าถึงDirและไฟล์ซึ่งมีประโยชน์สำหรับตัวเอง

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

นอกจากนี้ยังมีประโยชน์จาก STDLIB เป็น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)

ซึ่งค่อนข้างดี


110

อย่างที่คนอื่นพูดไปแล้วบรรทัดแรกของคุณควรเป็น

#!/usr/bin/env ruby

และคุณต้องทำให้มันปฏิบัติการได้: (ในเชลล์)

chmod +x test.rb

จากนั้นตามด้วยรหัสทับทิม หากคุณเปิดไฟล์

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

ไฟล์จะถูกเปิดในไดเรกทอรีปัจจุบันที่คุณจะได้รับpwdจากเปลือก

เส้นทางสู่สคริปต์ของคุณนั้นง่ายมาก เมื่อ$0คุณได้รับอาร์กิวเมนต์แรกของเชลล์ซึ่งเป็นเส้นทางสัมพัทธ์กับสคริปต์ของคุณ เส้นทางที่แน่นอนสามารถกำหนดได้ดังนี้

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

สำหรับการทำงานของระบบไฟล์ฉันมักใช้ Pathname นี่เป็น wrapper สำหรับคลาสอื่น ๆ ที่เกี่ยวข้องกับระบบไฟล์ ยังมีประโยชน์: Dir, ไฟล์ ...


66

นี่คือสิ่งที่สำคัญที่ขาดหายไปจากคำตอบอื่น ๆ : พารามิเตอร์บรรทัดคำสั่งสัมผัสกับ Ruby shell script ของคุณผ่านอาร์เรย์ ARGV (ทั่วโลก)

ดังนั้นหากคุณมีสคริปต์ชื่อ my_shell_script:

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

... ทำให้ปฏิบัติการ (ตามที่คนอื่นพูดถึง):

chmod u+x my_shell_script

และเรียกมันว่า:

> ./my_shell_script one two three four five

คุณจะได้รับสิ่งนี้:

I was passed: 
one
two
three
four
five

อาร์กิวเมนต์ทำงานได้ดีกับการขยายชื่อไฟล์:

./my_shell_script *

I was passed: 
a_file_in_the_current_directory
another_file    
my_shell_script
the_last_file

ส่วนใหญ่ทำงานได้กับ UNIX (Linux, Mac OS X) เท่านั้น แต่คุณสามารถทำสิ่งที่คล้ายกัน (แม้ว่าจะสะดวกน้อยกว่า) ใน Windows


32

มีคำแนะนำที่ดีมากมายที่นี่ดังนั้นฉันต้องการเพิ่มอีกนิด

  1. Backticks (หรือติ๊กด้านหลัง) ช่วยให้คุณทำสิ่งสคริปต์ได้ง่ายขึ้นมาก พิจารณา

    puts `find . | grep -i lib`
  2. หากคุณพบปัญหาในการรับเอาต์พุตของ backticks สิ่งที่กำลังจะผิดพลาดมาตรฐานแทนที่จะเป็นมาตรฐาน ใช้คำแนะนำนี้

    out = `git status 2>&1`
  3. Backticks ทำการแก้ไขสตริง:

    blah = 'lib'
    `touch #{blah}`
  4. คุณสามารถไพพ์ภายใน Ruby ได้เช่นกัน มันเป็นลิงค์ไปยังบล็อกของฉัน แต่มันลิงก์กลับมาที่นี่ดังนั้นก็ไม่เป็นไร :) อาจมีสิ่งที่ก้าวหน้ากว่าในหัวข้อนี้

  5. ตามที่คนอื่น ๆ ระบุไว้ถ้าคุณต้องการจริงจังนั่นก็คือ Rush: ไม่ใช่แค่การแทนที่เชลล์ (ซึ่งค่อนข้างตลกเกินไปสำหรับฉัน) แต่ยังเป็นไลบรารีสำหรับการใช้งานของคุณในเชลล์สคริปต์และโปรแกรม


สำหรับ Mac ให้ใช้ Applescript ใน Ruby เพื่อเพิ่มพลัง นี่คือshell_hereสคริปต์ของฉัน:

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

`osascript -e "${cmd}"`

ฉันแค่ต้องเยื้องรหัสพื้นที่เพิ่มเติม 4 สำหรับพวกเขาที่จะจัดรูปแบบ ฉันใส่ backticks กลับมาด้วย แต่ฉันไม่รู้ว่า Ruby เป็นอะไรที่ดีดังนั้นคุณต้องตรวจสอบเพื่อให้แน่ใจว่าเป็นสิ่งที่คุณตั้งใจไว้
Bill the Lizard

@Bill the Lizard ใช่นั่นคือ 'เคล็ดลับ' ที่ฉันต้องการ: เยื้องสองครั้ง ขอบคุณสำหรับความช่วยเหลือ
Dan Rosenstark

1
ฉันคิดว่า Rush ตายแล้ว: groups.google.com/group/ruby-shell/browse_thread/thread/…
Dan Rosenstark

22

ไปรับตัวเองสำเนาของชีวิตประจำวันการเขียนสคริปต์กับทับทิม มันมีเคล็ดลับที่มีประโยชน์มากมายเกี่ยวกับวิธีการทำสิ่งต่าง ๆ ที่คุณต้องการทำ


2
หนังสือที่ดีฉันกำลังอ่านอยู่ตอนนี้มันให้ความรู้สึกเหมือนการเดินทางรหัสเซน และถ้าคุณไม่รู้ TDD คุณจะได้เรียนรู้พื้นฐานของ TDD ไปพร้อมกัน
Sébastien RoccaSerra

ฉันคิดว่าหนังสือเล่มนี้มีข้อมูลที่ดี แต่มีค่าใช้จ่ายมากสำหรับโปรแกรมเมอร์ที่มีประสบการณ์
D รวม

12

สิ่งนี้อาจมีประโยชน์: http://rush.heroku.com/

ฉันไม่ได้ใช้มันมากนัก แต่ดูเท่ห์ดี

จากเว็บไซต์:

รัชคือการแทนที่เชลล์ยูนิกซ์ (ทุบตี, zsh, ฯลฯ ) ซึ่งใช้ไวยากรณ์ทับทิมบริสุทธิ์ Grep through files, ค้นหาและฆ่าโพรเซส, คัดลอกไฟล์ - ทุกอย่างที่คุณทำในเชลล์, ตอนนี้เป็น Ruby


2
Rush: ไม่ ทำไม? groups.google.com/group/ruby-shell/browse_thread/thread/…มันยอดเยี่ยม แต่ไม่มีใครอยู่ในวงล้อ
Dan Rosenstark

12

สมมติว่าคุณเขียนscript.rbสคริปต์ของคุณ ใส่:

#!/usr/bin/env ruby

เป็นบรรทัดแรกและทำ chmod +x script.rb


7

เมื่อคุณต้องการเขียนสคริปต์ ruby ​​ที่ซับซ้อนมากขึ้นเครื่องมือเหล่านี้อาจช่วยได้:

ตัวอย่างเช่น:

  • ธ อร์ (กรอบการเขียนสคริปต์)

  • gli (git like interface)

  • เมทาโดน (สำหรับการสร้างเครื่องมืออย่างง่าย)

พวกเขาให้คุณเริ่มต้นอย่างรวดเร็วในการเขียนสคริปต์ของคุณเองโดยเฉพาะ 'แอปบรรทัดคำสั่ง'


5

คำตอบข้างต้นมีความน่าสนใจและมีประโยชน์มากเมื่อใช้ Ruby เป็น shell script สำหรับฉันฉันไม่ได้ใช้ทับทิมเป็นภาษาประจำวันของฉันและฉันชอบที่จะใช้ทับทิมเป็นตัวควบคุมการไหลเท่านั้นและยังคงใช้ทุบตีในการทำงาน

ฟังก์ชันตัวช่วยบางอย่างสามารถใช้สำหรับทดสอบผลการดำเนินการ

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

ด้วยผู้ช่วยสคริปต์ทับทิมอาจทุบตีเหมือนกัน:

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

ชายนี่เยี่ยมมากขอบคุณ!
Victor Martins

4

"ฉันจะเขียนทับทิมอย่างไร" อยู่เหนือขอบเขตของ SO เล็กน้อย

แต่หากต้องการเปลี่ยนสคริปต์ทับทิมเหล่านี้ให้เป็นสคริปต์ที่ใช้งานได้ให้วางสิ่งนี้เป็นบรรทัดแรกของสคริปต์ทับทิมของคุณ:

#!/path/to/ruby

จากนั้นทำให้ไฟล์ที่ปฏิบัติการได้:

chmod a+x myscript.rb

และไปคุณไป


4

วางสิ่งนี้ไว้ที่จุดเริ่มต้นของสคริปต์ของคุณ

#!/usr/bin/env ruby

จากนั้นทำเครื่องหมายว่าปฏิบัติการได้:

chmod +x script.rb

3

คำตอบโดยwebmatสมบูรณ์แบบ ฉันแค่อยากจะชี้ให้คุณเพิ่ม หากคุณมีการจัดการจำนวนมากที่มีพารามิเตอร์บรรทัดคำสั่งสำหรับสคริปต์ของคุณคุณควรใช้optparse มันง่ายและช่วยให้คุณอย่างมาก


3

ในทับทิมค่าคงที่__FILE__จะให้เส้นทางของสคริปต์ที่คุณใช้อยู่เสมอ

บน Linux /usr/bin/envคือเพื่อนของคุณ:

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

ใน Windows มันขึ้นอยู่กับว่าไฟล์. rb เชื่อมโยงกับทับทิมหรือไม่ ถ้าเป็น:

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

หากไม่ใช่คุณจำเป็นต้องเรียกใช้ ruby ​​อย่างชัดเจนฉันใช้ไฟล์. cmd ระดับกลาง:

my_script.cmd:

@ruby %~dp0\my_script.rb

my_script.rb:

puts File.expand_path(__FILE__)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.