168

我有一些我想做的简单的 shell 脚本任务

例如:从与某个正则表达式匹配的文件列表中选择工作目录中的文件。

我知道我可以使用标准的 bash 和 grep 来做这种事情,但是我很高兴能够破解可以在 windows 和 linux 中运行的快速脚本,而不必记住一堆命令行程序和标志等。

我试图做到这一点,但最终对我应该从哪里获取信息(例如对当前目录的引用)感到困惑

所以问题是我需要知道 Ruby 库的哪些部分来编写 ruby​​ shell 脚本?

4

13 回答 13

150

默认情况下,您已经可以访问DirFile,它们本身就非常有用。

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

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)

这是相当不错的

于 2008-10-03T13:30:59.110 回答
111

正如其他人已经说过的那样,您的第一行应该是

#!/usr/bin/env ruby

而且您还必须使其可执行:(在外壳中)

chmod +x test.rb

然后遵循 ruby​​ 代码。如果你打开一个文件

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

该文件在您pwd在 shell 中获得的当前目录中打开。

脚本的路径也很容易获得。随着$0您获得 shell 的第一个参数,它是脚本的相对路径。绝对路径可以这样确定:

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

对于文件系统操作,我几乎总是使用 Pathname。这是许多其他文件系统相关类的包装器。也很有用:目录、文件...

于 2008-10-03T11:41:04.480 回答
68

这是其他答案中缺少的重要内容:命令行参数通过 ARGV(全局)数组暴露给您的 Ruby shell 脚本。

因此,如果您有一个名为 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 中执行类似(尽管不太方便)的操作。

于 2009-11-27T05:52:03.483 回答
33

这里有很多好的建议,所以我想再补充一点。

  1. 反引号(或反引号)使您可以更轻松地编写一些脚本。考虑

    puts `find . | grep -i lib`
    
  2. 如果您在获取反引号输出时遇到问题,则这些内容将变为标准错误而不是标准输出。使用这个建议

    out = `git status 2>&1`
    
  3. 反引号做字符串插值:

    blah = 'lib'
    `touch #{blah}`
    
  4. 你也可以在 Ruby 中使用管道。这是我博客的链接,但它链接回这里,所以没关系:) 关于这个主题可能有更高级的东西。

  5. 正如其他人所指出的,如果您想认真一点,那么 Rush:不仅可以作为 shell 替代品(这对我来说有点太滑稽了),而且还可以作为您在 shell 脚本和程序中使用的库。


在 Mac 上,在 Ruby 中使用 Applescript 以获得更多功能。这是我的shell_here脚本:

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

`osascript -e "${cmd}"`
于 2010-03-06T13:29:15.493 回答
22

去为自己获取一份使用 Ruby 编写日常脚本的副本。它有很多关于如何做你想做的事情的有用提示。

于 2008-10-03T12:42:06.650 回答
12

假设您编写script.rb脚本。放:

#!/usr/bin/env ruby

作为第一行并做一个chmod +x script.rb

于 2008-10-03T11:14:23.110 回答
12

这也可能有帮助:http ://rush.heroku.com/

我用的不多,但看起来很酷

从网站:

rush 是使用纯 Ruby 语法的 unix shell(bash、zsh 等)的替代品。grep 遍历文件、查找和终止进程、复制文件 - 您在 shell 中所做的一切,现在都在 Ruby 中

于 2008-10-05T09:29:29.003 回答
7

当您想编写更复杂的 ruby​​ 脚本时,这些工具可能会有所帮助:

例如:

  • thor(一个脚本框架)

  • gli(类似 git 的界面)

  • 美沙酮(用于创建简单工具)

它们让您快速开始编写自己的脚本,尤其是“命令行应用程序”。

于 2013-03-19T07:59:46.080 回答
5

“我如何编写 ruby​​”有点超出 SO 的范围。

但是要将这些 ruby​​ 脚本转换为可执行脚本,请将其作为 ruby​​ 脚本的第一行:

#!/path/to/ruby

然后使文件可执行:

chmod a+x myscript.rb

你走了。

于 2008-10-03T11:07:18.613 回答
5

当使用 Ruby 作为 shell 脚本时,上面的答案很有趣并且非常有用。对我来说,我不使用 Ruby 作为我的日常语言,我更喜欢仅使用 ruby​​ 作为流控制,并且仍然使用 bash 来完成任务。

一些辅助函数可用于测试执行结果

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

使用 helper,ruby 脚本可以与 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
于 2016-12-01T17:10:47.727 回答
4

把它放在你 script.rb 的开头

#!/usr/bin/env ruby

然后将其标记为可执行文件:

chmod +x script.rb
于 2008-10-03T11:37:45.357 回答
3

在 ruby​​ 中,常量__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 文件是否与 ruby​​ 相关联。如果他们是:

# 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__)
于 2008-10-03T12:18:29.397 回答
3

webmat的答案是完美的。我只是想给你指出一个补充。如果你必须为你的脚本处理很多命令行参数,你应该使用optparse。它很简单,可以极大地帮助您。

于 2012-08-30T18:22:13.897 回答