为什么从 ' 更改为 " 会影响这一行的行为?

why does changing from ' to " affect the behavior of this one-liner?

为什么简单地改变用 ' 而不是 " 包围我的一行会影响代码的行为?第一行代码产生了预期的结果,第二行代码给出了(对我来说!)一个意想不到的结果,打印出一个意想不到的数组引用。

$ echo "puke|1|2|3|puke2" | perl -lne 'chomp;@a=split(/\|/,$_);print $a[4];'
puke2
$ echo "puke|1|2|3|puke2" | perl -lne "chomp;@a=split(/\|/,$_);print $a[4];"

这是 Perl 版本:

$ perl -v

This is perl, v5.10.1 (*) built for x86_64-linux-thread-multi

ARRAY(0x1f79b98)

这实际上是一个 shell 主题,而不是 perl 主题。

在shell中:

单引号保留其包含的所有字符的字面值,包括 $ 和反斜杠。但是,对于双引号,$、反引号和反斜杠字符具有特殊含义。

例如:

'\"' 的计算结果为 \"

"\'" 的计算结果仅为 '

因为使用双引号,反斜杠作为转义字符具有特殊含义。

使用双引号让 shell 首先插入变量。

如您所见,$_$a 在父 shell 为管道分叉的子 shell 中未设置。请参阅下面对 $_ 的评论。

所以双引号版本有效

echo "puke|1|2|3|puke2" | perl -lne 'chomp;@a=split(/\|/);print [4];'

什么打印 arrayref [4]


评论 $_ 接触 Bash 的影响。感谢 Borodin 提出这个问题。

$_ 是 Bash 中为数不多的 special shell parameters 之一。它包含前一个命令的最后一个参数,或者调用 shell 或命令的路径名(通过 _ 环境变量)。有关完整说明,请参阅 link。

然而,这里它被解释为分叉到 运行 perl 命令的子shell,这是第一个。显然它甚至没有设置,如

所示
echo hi;  echo hi | echo $_

打印一个空行(在第一个 hi 之后)。原因可能是 _ 环境变量没有为管道的 subshell 设置,但我不明白为什么会这样。例如,

echo hi; (echo $_)

使用 hi 打印两行,即使 ( ) 启动子 shell.

无论如何,未设置给定管道中的 $_

split 部分然后是 split(/\|/),因此通过默认 split(/\|/, $_) -- 没有任何东西可以拆分。随着 -w 添加,这确实打印了使用未初始化的 $_.

的警告

请注意,此行为取决于 shell。 tcsh 根本不会 运行 带有双引号。在 kshzsh 管道的最后一部分 运行s 在主 shell 中,而不是子 shell,所以 $_ 在那里。