Skip to content

Ruby 预定义变量

Ruby 提供了一组特殊的预定义全局变量。其中许多变量具有简短、隐晦的名称(通常是 $ 后跟一个字符)。虽然它们在编写短脚本或在 IRB 中快速调试时可能很方便,但在大型应用或库中通常不鼓励使用它们,因为它们的全局性质可能会降低代码可读性。

许多这些变量都有更具可读性的替代方案,可以通过标准方法实现,或者通过 require English 模块(require 'English')来提供描述性别名。

下表列出了常见的预定义变量、它们的 English 模块别名(如果可用)以及描述:

变量English 别名描述
$!$ERROR_INFOraise 抛出的最后一个异常对象。由 rescue 设置。如果没有异常则为 nil。
$@$ERROR_POSITIONraise 抛出的最后一个异常的栈回溯(字符串数组)。对于特定的异常对象,请使用 exception.backtrace。
$_$LAST_READ_LINE在当前作用域内,gets 或 readline 读取的最后一个字符串。
$.$INPUT_LINE_NUMBER, $NRgets 或 ARGF 读取的最后一个文件的当前输入行号。
$/$INPUT_RECORD_SEPARATOR, $RS输入记录分隔符(一个字符串,默认为换行符 \n)。gets 读取直到遇到此分隔符。
$\$OUTPUT_RECORD_SEPARATOR, $ORSprint 和 IO#write 的输出记录分隔符(默认为 nil)。如果设置,它会在每次输出后打印。
$,$OUTPUT_FIELD_SEPARATOR, $OFSprint 参数之间以及 Array#join 默认使用的输出分隔符(默认为 nil)。
$;$FIELD_SEPARATOR, $FS当未给出参数时,String#split 的默认分隔符(默认为 nil,表示按空白字符分割)。
$~$LAST_MATCH_INFO在当前作用域内,上一次成功的正则表达式匹配产生的 MatchData 对象。对于全局的最后匹配,请使用 Regexp.last_match。
`$PREMATCH上一次成功的 regex 匹配左侧的字符串。来自 Regexp.last_match.pre_match。
$&$MATCH上一次成功的 regex 匹配所匹配的字符串。来自 Regexp.last_match[0]。
$‘$POSTMATCH上一次成功的 regex 匹配右侧的字符串。来自 Regexp.last_match.post_match。
$+$LAST_PAREN_MATCH上一次成功的 regex 匹配中,编号最高的捕获组所匹配的文本。
$1, $2, … $NN/A上一次成功的 regex 匹配捕获的第 N 个组的文本。例如,$1 等同于 Regexp.last_match[1]。
$0$PROGRAM_NAME当前正在执行的 Ruby 脚本文件的名称。
$*$ARGVARGV 的别名,是传递给脚本的命令行参数数组。
$$$PROCESS_ID, $PID当前正在运行的 Ruby 脚本的进程 ID (PID)。
$?$CHILD_STATUS上一个执行的子进程的退出状态(一个 Process::Status 对象)。
$LOAD_PATH, $:$LOAD_PATH当使用 require 或 load 加载文件时,Ruby 搜索的目录数组。
$“$LOADED_FEATURES已经加载(通过 require)的特性(文件)的文件名数组。
$DEBUG$DEBUG指示 Ruby 是否在调试模式下运行的标志(由 -d 命令行选项设置)。值为 true 或 false。
$VERBOSE$VERBOSE当前的详细程度级别。nil (静默), false (正常), true (详细)。由 -w 或 -v 选项设置。
$stdin$stdin标准输入流对象(默认为 STDIN)。
$stdout$stdout标准输出流对象(默认为 STDOUT)。
$stderr$stderr标准错误流对象(默认为 STDERR)。
$SAFE (Deprecated)N/A安全级别。在 Ruby 2.7 中已弃用,在 Ruby 3.0 中已移除。其值范围为 0-4,用于控制安全限制。
$-a, $-d, $-F, $-I, $-l, $-p, $-v, $-w, $-0N/A这些变量反映了传递给 Ruby 解释器的各种命令行选项的状态。例如,$-d 是 $DEBUG 的别名。
#!/usr/bin/env ruby
require 'English'
# 在匹配后使用 $~ 和 $1 的示例
"hello world".match(/(\w+) (\w+)/)
puts "Full match ($& or $MATCH): #{$MATCH}"
puts "First capture ($1): #{$1}"
puts "Second capture ($2): #{$2}"
# 在 rescue 块中使用 $! 和 $@ 的示例
begin
1 / 0
rescue ZeroDivisionError
puts "Error type ($! or $ERROR_INFO): #{$ERROR_INFO.class}"
puts "Error message: #{$ERROR_INFO.message}"
puts "Backtrace ($@ or $ERROR_POSITION):"
$ERROR_POSITION.first(2).each { |line| puts " #{line}" }
end
puts "Script name ($0 or $PROGRAM_NAME): #{$PROGRAM_NAME}"
puts "Arguments ($* or $ARGV): #{$ARGV.inspect}"
puts "PID ($$ or $PROCESS_ID): #{$PROCESS_ID}"
  • 优先使用显式方法和对象:不要依赖 $!,而是使用传递给 rescue => e 的异常对象。对于 MatchData,将 String#match 的结果赋值给一个变量。
  • 使用 English 模块:如果你发现自己需要使用这些全局变量,require 'English' 可以通过提供描述性别名(例如,$ERROR_INFO 代替 $!)来大大提高代码可读性。
  • 限制作用域:如果使用这些变量,其影响范围应被理解并加以限制,通常仅限于非常小的脚本或特定的局部上下文。
  • 避免修改大多数这些变量:虽然有些变量(如 $/ 或 $,)可以修改,但在大型程序或库中修改全局状态可能会导致意外行为。

许多这些变量是 Perl 对 Ruby 早期设计影响的遗留物。现代 Ruby 风格更倾向于使用更显式和面向对象的方法。

更多详细信息,请查阅官方 Ruby 文档中关于预定义变量的部分:https://ruby-doc.org/docs/ruby-doc-bundle/UsersGuide/rg/globalvars.html