Ruby命令行隐式条件检查

Sha*_*awn 9 ruby shell

我从一个bash shell运行以下命令:

echo 'hello world' | ruby -ne 'puts $_ if /hello/'
Run Code Online (Sandbox Code Playgroud)

我一开始以为这是一个拼写错误,但hello world令人惊讶的输出.

我打算输入:

echo 'hello world' | ruby -ne 'puts $_ if /hello/ === $_'
Run Code Online (Sandbox Code Playgroud)

任何人都可以给出解释,或指向文档,为什么我们得到这种隐式比较$_

我还要注意:

echo 'hello world' | ruby -ne 'puts $_ if /test/'
Run Code Online (Sandbox Code Playgroud)

不输出任何东西.

mat*_*att 4

Ruby 解析器对于条件中的正则表达式文字有一个特殊情况。通常(即不使用e,np命令行选项)此代码:

\n\n
if /foo/\n  puts "TRUE!"\nend\n
Run Code Online (Sandbox Code Playgroud)\n\n

产生:

\n\n
if /foo/\n  puts "TRUE!"\nend\n
Run Code Online (Sandbox Code Playgroud)\n\n

分配与正则表达式匹配的内容$_,如下所示:

\n\n
$_ = \'foo\'\nif /foo/\n  puts "TRUE!"\nend\n
Run Code Online (Sandbox Code Playgroud)\n\n

产生:

\n\n
$ ruby regex-in-conditional1.rb\nregex-in-conditional1.rb:1: warning: regex literal in condition\n
Run Code Online (Sandbox Code Playgroud)\n\n

这是 Ruby 条件的正常规则的一个(记录很少)例外,其中任何 \xe2\x80\x99s 不falsenil评估为真的东西。

\n\n

这仅适用于正则表达式文字,以下行为与您对条件的预期相同:

\n\n
regex = /foo/\nif regex\n  puts "TRUE!"\nend\n
Run Code Online (Sandbox Code Playgroud)\n\n

输出:

\n\n
$_ = \'foo\'\nif /foo/\n  puts "TRUE!"\nend\n
Run Code Online (Sandbox Code Playgroud)\n\n

这是在解析器中处理的。在 MRI 代码中搜索警告文本会产生一个匹配项parse.y

\n\n
case NODE_DREGX:\ncase NODE_DREGX_ONCE:\n warning_unless_e_option(parser, node, "regex literal in condition");\n return NEW_MATCH2(node, NEW_GVAR(rb_intern("$_")));\n
Run Code Online (Sandbox Code Playgroud)\n\n

我不认识 Bison,所以我可以准确解释这里发生的事情,但你可以推断出一些线索。如果已设置该选项,该函数只会warning_unless_e_option抑制警告,因为在正常代码中不鼓励使用此功能,但在命令行表达式中可能很有用(这解释了为什么您在代码中看不到警告) -e。下一行似乎正在构建一个解析子树,它是正则表达式和$_全局变量之间的正则表达式匹配,其中包含 \xe2\x80\x9c [t]he 最后一个输入行的字符串 by gets 或 readline \xe2\x80\ x9d。然后这些节点将被编译到通常的正则表达式方法调用中。

\n\n

这显示了正在发生的事情,I\xe2\x80\x99ll 只是引用文档中的内容来结束Kernel#gets中的一段话来结束,这可能解释了为什么这是一个如此晦涩的功能

\n\n
\n

使用 $_ 作为隐式参数的编程风格逐渐在 Ruby 社区中失去青睐。

\n
\n