How do I use Ruby for shell scripting?
我有一些简单的shell脚本编写任务,我想做
例如:从与某些正则表达式匹配的文件列表中选择工作目录中的文件。
我知道我可以使用标准的bash和grep做这种事情,但我很高兴能够破解可以在windows和linux中运行的快速脚本,而不必记住一堆命令行程序和标志等。
我试图实现这一目标,但最终对我应该获取信息的地方感到困惑,例如对当前目录的引用
所以问题是编写ruby shell脚本需要知道Ruby库的哪些部分?
默认情况下,您已经可以访问Dir和File,它们本身非常有用。
1 2 3 4 5 6 7 8 9 10 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | 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) |
这很不错
正如其他人已经说过的那样,你的第一行应该是
1 | #!/usr/bin/env ruby |
而且你还必须使它可执行:(在shell中)
1 | chmod +x test.rb |
然后遵循ruby代码。如果你打开一个文件
1 2 3 | File.open("file","r") do |io| # do something with io end |
该文件在shell中使用
脚本的路径也很简单。使用
1 2 3 | #!/usr/bin/env ruby require 'pathname' p Pathname.new($0).realpath() |
对于文件系统操作,我几乎总是使用Pathname。这是许多其他文件系统相关类的包装器。也很有用:Dir,File ......
以下是其他答案中缺少的重要内容:命令行参数通过ARGV(全局)数组公开给您的Ruby shell脚本。
所以,如果你有一个名为my_shell_script的脚本:
1 2 3 4 5 | #!/usr/bin/env ruby puts"I was passed:" ARGV.each do |value| puts value end |
...让它可执行(正如其他人提到的):
1 | chmod u+x my_shell_script |
并称之为:
1 | > ./my_shell_script one two three four five |
你会得到这个:
1 2 3 4 5 6 | I was passed: one two three four five |
参数与文件名扩展很好地配合:
1 2 3 4 5 6 7 | ./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中执行类似(虽然不太方便)的操作。
这里有很多好建议,所以我想多补充一点。
反引号(或反向标记)可以让你更轻松地编写脚本。考虑
1 | puts `find . | grep -i lib` |
如果你在获得反引号的输出时遇到问题,那么这些东西将是标准错误而不是标准输出。使用这个建议
1 | out = `git status 2>&1` |
反引号进行字符串插值:
1 2 | blah = 'lib' `touch #{blah}` |
你也可以在Ruby里面管道。它是我的博客的链接,但它链接回来,所以没关系:)这个主题可能有更多高级的东西。
正如其他人所指出的那样,如果你想认真对待Rush:不仅仅是作为shell替换(对我来说有点太过分了),而且还作为一个用于shell脚本和程序的库。
在Mac上,使用Ruby内部的Applescript获得更多功能。这是我的
1 2 3 4 5 6 | #!/usr/bin/env ruby `env | pbcopy` cmd = %Q@tell app"Terminal" to do script"$(paste_env)"@ puts cmd `osascript -e"${cmd}"` |
使用Ruby获取Everyday Scripting的副本。它有很多关于如何做你想要做的事情的有用提示。
这可能也有帮助:http://rush.heroku.com/
我没有用太多,但看起来很酷
从网站:
rush is a replacement for the unix shell (bash, zsh, etc) which uses pure Ruby syntax. Grep through files, find and kill processes, copy files - everything you do in the shell, now in Ruby
假设您编写了
1 | #!/usr/bin/env ruby |
作为第一行并做一个
当您想编写更复杂的ruby脚本时,这些工具可能有所帮助:
例如:
-
thor(脚本框架)
-
gli(git like interface)
-
美沙酮(用于创建简单的工具)
它们使您可以快速开始编写自己的脚本,尤其是"命令行应用程序"。
当使用Ruby作为shell脚本时,上面的答案很有趣并且非常有用。 对我来说,我不使用Ruby作为我的日常语言,我更喜欢使用ruby作为流量控制而仍然使用bash来完成任务。
一些辅助函数可用于测试执行结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | #!/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 " if (not $?.success?) and raise_on_error return $?.success? end def print_exit(message) print"#{message} " exit end module_function :execute, :print_exit, :test end |
使用帮助程序,ruby脚本可能是bash相似的:
1 2 3 4 5 6 7 8 9 10 | #!/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 |
将它放在script.rb的开头
1 | #!/usr/bin/env ruby |
然后将其标记为可执行:
1 | chmod +x script.rb |
"我怎么写ruby"有点超出了SO的范围。
但是要将这些ruby脚本转换为可执行脚本,请将其作为ruby脚本的第一行:
1 | #!/path/to/ruby |
然后使文件可执行:
1 | chmod a+x myscript.rb |
然后你走吧
网络摄像头的答案是完美的。我只想指出你的补充。如果必须为脚本处理命令行参数很多,则应使用optparse。它很简单,可以帮助您。
在ruby中,常量
在Linux上,
1 2 3 4 | #! /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相关联。
如果它们是:
1 2 | # This script filename must end with .rb puts File.expand_path(__FILE__) |
如果不是,你必须在它们上显式调用ruby,我使用一个中间的.cmd文件:
my_script.cmd:
1 | @ruby %~dp0\my_script.rb |
my_script.rb:
1 | puts File.expand_path(__FILE__) |