Ruby 命令行隐式条件检查

标签 ruby shell

我从 bash shell 运行了以下命令:

echo 'hello world' | ruby -ne 'puts $_ if /hello/'

一开始以为是打错了,没想到竟然输出了hello world

我想输入:

echo 'hello world' | ruby -ne 'puts $_ if /hello/ === $_'

谁能给出解释或指向文档,说明为什么我们得到与 $_ 的这种隐式比较?

我还要注意:

echo 'hello world' | ruby -ne 'puts $_ if /test/'

不会输出任何东西。

最佳答案

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

if /foo/
  puts "TRUE!"
end

产生:

$ ruby regex-in-conditional1.rb
regex-in-conditional1.rb:1: warning: regex literal in condition

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

$_ = 'foo'
if /foo/
  puts "TRUE!"
end

产生:

$ ruby regex-in-conditional2.rb
regex-in-conditional2.rb:2: warning: regex literal in condition
TRUE!

这是 Ruby 条件规则的一个(记录不详的)异常(exception),其中任何不是 falsenil 的东西都被评估为 truthy。

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

regex = /foo/
if regex
  puts "TRUE!"
end

输出:

$ ruby regex-in-conditional3.rb
TRUE!

这是在解析器中处理的。在 MRI 代码中搜索警告文本会生成单个 match in parse.y。 :

case NODE_DREGX:
case NODE_DREGX_ONCE:
 warning_unless_e_option(parser, node, "regex literal in condition");
 return NEW_MATCH2(node, NEW_GVAR(rb_intern("$_")));

我不了解 Bison,所以我无法准确解释这里发生了什么,但是您可以推断出一些线索。 warning_unless_e_option如果设置了 -e 选项,函数只是抑制警告,因为在普通代码中不鼓励使用此功能,但在命令行的表达式中可能很有用(这解释了为什么你看不到警告在你的代码中)。下一行似乎是在构建一个解析子树,它是正则表达式和 $_ 全局变量之间的正则表达式匹配,其中包含“[t]he last input line of string by gets or readline”。 ”。然后这些节点将被编译成通常的正则表达式方法调用。

这显示了正在发生的事情,我将以 Kernel#gets documentation 中的引述作为结束。这可以解释为什么这是一个如此晦涩的功能

The style of programming using $_ as an implicit parameter is gradually losing favor in the Ruby community.

关于Ruby 命令行隐式条件检查,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30631728/

相关文章:

ruby - 如何使用 ruby​​zip 解压缩压缩文件夹

linux - 在 linux 中使用自定义别名中的 find 命令没有得到结果

linux - 在 Unix 中,递归搜索文件并检索文件而不仅仅是文件路径的命令

Python:将 wx.py.shell.Shell 插入单独的进程

xml - 使用 awk 命令提取 xml 标签值

c - Linux终端中的shell程序

ruby-on-rails - 在开发模式下重新加载 Rails 3 初始值设定项

ruby - 如何使用 Chef 设置环境变量?

ruby - 在 Ruby 中按多个条件排序

ruby - 如何使用#each 将所有哈希值增加三倍?