闲着无聊,我们来看一下 Ruby 中的命令行参数 ( Command-line Arguments ) 那些事。本章节会涉及到以下几个知识点
ARGV
数组- 奇怪 ( weird ) 的
ARGF
对象 my_cat.rb
ARGV 数组
我们先来了解下 ARGV
数组。
ARGV
是 ARGument Vector
的缩写
因为向量 ( vector ) 是一个一维数组,所以 ARGV
也是一个一维数组。
ARGV
包含了以给定命令行顺序插入的参数的完整列表。
我们用一个小片段来看看 ARGV
是如何存储命令行参数的。
$> cat list_argv.rb p ARGV.class p ARGV $> ruby list_argv.rb arg1 arg2 arg3 Array ["arg1", "arg2", "arg3"]
从上面的代码中可以看出,ARGV
是一个数组,包含了按照原始顺序传递给 ruby list_argv.rb
程序的三个命令行参数 ["arg1", "arg2", "arg3"]
需要注意的是,程序名 list_argv.rb
并没有包含在 ARGV
数组中。虽然其它语言,比如 C 是包含的。
ARGV 对象
ARGV
是一个流 ( stream ) ,设计初衷是在脚本中用来处理作为命令行参数传递的文件或传递给STDIN
输入流的文件。
ARGF 是一个 「 硬编码类 」 ( hard-coded class ) ,类名为 ARGF.class
irb> ARGF ARGF irb> ARGF.class ARGF.class irb> ARGF.class.class Class
从上面的代码中可以看出,ARGF
是 ARGF.class
的一个实例,而 ARGF.class
则是一个类。
我们再来看看 ARGV
的祖先链又是怎么样的
irb> ARGF.class.ancestors => [ARGF.class, Enumerable, Object, Kernel, BasicObject]
ARGF
与 IO
类共享一套方法,如 read
,each_line
等。
ARGV
同样还包含了 Enumerable
模块,这意味着它可以作为对象的集合
接下来,我们通过实例来看看 ARGF
的目的是什么。
如果你不熟悉 「 祖先链 」 相关的知识,可以阅读我们的文章 Ruby 中的对象模型 ( object model ) ( 上 )
my_cat.rb
我们可以使用 cat 这个命令行命令连接并输出多个文件的内容。
$> cat test1 test2 I'm test1 I'm test2 $> echo "STDIN" | cat STDIN $> echo "STDIN" | cat test1 - test2 I'm test1 STDIN I'm test2
上面的代码中,cat
按顺序读取文件,并将它们写入标准输出 ( STDOUT
)
所有的文件会按照命令行顺序进行处理。
如果其中一个文件是单个短划线 ( -
) 或缺省了,则 cat
命令会从标准输入 ( STDIN ) 读取它
很酷,对吧。
现在,我们来看看如何在 Ruby 中实现同样的功能。
首先,创建一个文件 my_cat.rb
,然后输入以下内容
puts ARGF.read
然后按照下面的代码运行我们的 my_cat.rb
文件
$> ruby my_cat.rb test1 test2 I'm test1 I'm test2 $> echo "STDIN" | ruby my_cat.rb STDIN $> echo "STDIN" | ruby my_cat.rb test1 - test2 I'm test1 STDIN I'm test2 $> ruby my_cat.rb --verbose No such file or directory @ rb_sysopen - --verbose (Errno::ENOENT)
可以看到,我们 my_cat.rb
文件的输出结果和 cat
命令一模一样。
ARGF.read
同样会处理短划线 -
ARGF.read
会把 ARGV
数组中的每个命令行参数当作文件来处理,同样也会将短划线 ( -
) 当作标准输入来处理。
如果 ARGV
为空,那么 ARGF
会尝试从标准输入中读取内容。
注意
如果 ARGV
数组中的任意元素如果不是一个文件或文件对象,那么 ARGF
会抛出一个异常 No such file or directory
因此,在调用 ARGF
之前,需要对 ARGV
数组中的元素进行一些处理,删除那些不是文件也不是文件对象的参数。