【问题标题】:Why this single and double quote make so much difference in output为什么这个单引号和双引号会在输出中产生如此大的差异
【发布时间】:2013-08-21 10:03:29
【问题描述】:

为什么这两个命令的输出不同?

cat config.xml|perl -ne 'print $1,"\n" if /([0-9\.]+):161/'

cat config.xml|perl -ne "print $1,"\n" if /([0-9\.]+):161/"

First 按预期打印匹配组,而 seconds 打印整行。

【问题讨论】:

    标签: regex perl shell


    【解决方案1】:

    我发现你的命令有两个主要问题。

    首先,双引号允许 shell 插值,$1 将被用作 shell 变量并被替换。由于它不太可能存在,它将被替换为空字符串。因此,您得到的不是print $1,而是print,它是print $_ 的简写,这可能就是打印整行的原因。

    其次,您的命令中有未转义的双引号,因此您实际上是在将三个字符串传递给 Perl:

    print ,
    \n
     if /(....)/
    

    至于为什么或如何使用您的 shell,我不知道,因为我无法访问您的操作系统,也不知道它是哪一个。在 Windows 中,我收到 n (Unquoted string "n" may clash with future reserved word at -e line 1.) 的 Perl 裸字警告,这意味着 \n 被解释为字符串。现在,这是棘手的部分。我们得到的是这样的:

    print , \n if /.../
    

    这意味着\n 不再是print 的参数,它是print 之后的一个语句,并且它处于无效上下文中,因此它被忽略。我们可以通过这个警告看到这一点(我不得不在我的 shell 中伪造):

    Useless use of single ref constructor in void context at -e line 1.
    

    (请注意,您不会收到这些警告,因为您不使用警告——-w 开关)

    所以我们剩下的就是

    print if /.../
    

    这正是您描述的行为的代码:找到匹配项时打印整行。

    在 shell 中可视化问题的方法是将 -MO=Deparse 开关添加到单行中,如下所示:

    C:\perl>perl -MO=Deparse -ne"print ,"\n" if /a/"
    LINE: while (defined($_ = <ARGV>)) {
        print($_), \'n' if /a/;
    }
    -e syntax OK
    

    现在我们可以清楚地看到 print 语句与换行符是分开的,并且换行符是对字符串的引用。


    解决方案:

    但是,您的代码还有其他问题,如果处理得当,您可以避免所有 shell 问题。首先,您有一个UUOC (Useless Use of Cat)。当在命令行上使用-n 开关时,可以给 perl 一个文件参数。其次,您不需要为此使用变量,您可以简单地打印正则表达式的返回值:

    perl -nlwe 'print for /(...)/' config.xml
    

    -l 开关将为您处理换行符,在这种情况下,将换行符添加到打印中。 for 是避免打印空匹配项所必需的。

    【讨论】:

      【解决方案2】:

      在双引号内,一些东西被替换($variable, `command`, ..)。在单引号内时,它们保持原样。

      $ echo "$HOME"
      /home/falsetru
      $ echo '$HOME'
      $HOME
      
      $ echo "`echo 1`"
      1
      $ echo '`echo 1`'
      `echo 1`
      

      嵌套引号:

      $ echo ""hello""
      hello
      $ echo '"hello"'
      "hello"
      $ echo "\"hello\""
      "hello"
      

      转义双引号,$ 得到相同的结果:

      cat config.xml | perl -ne "print \$1,\"\n\" if /([0-9\.]+):161/"
      

      【讨论】:

        【解决方案3】:

        两件事:

        1. 嵌套引号。
        2. 变量扩展方式不同。

        第一个命令有一个字符串,恰好包含一些双引号。变量没有展开。

        第二个命令有两个字符串,中间有一个不带引号的\n。变量扩展了。

        假设$1 包含“blah”

        第一个将这个字符串传递给perl:

        print $1,"\n" if /([0-9\.]+):161/
        

        第二个,这个:

        print blah,\n if /([0-9\.]+):161/
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-06-07
          • 2012-04-06
          • 2017-05-14
          • 2010-12-31
          • 2010-10-30
          相关资源
          最近更新 更多