【问题标题】:Changing the input record seperator to \n or \r when parsing lines解析行时将输入记录分隔符更改为 \n 或 \r
【发布时间】:2014-03-03 20:16:09
【问题描述】:

我有一个 perl 脚本,它读取来自另一个进程的输出(逐行),进行一些处理并输出结果:

#!/bin/bash 
set -e
set -o pipefail

RUN.SH ${@} 2>&1 | perl -M"Term::ANSIColor" -wnl -e '
m/ERROR/i and print "\e[1;91m", "$_", "\e[0m" 
or print;'

而且效果很好,除非进程 RUN.SH 的输出没有以新行 (\n) 结束,而是以 \r 结束!在这种情况下,这个 Perl 解析器在下一个 \n 之前不会打印任何内容。我需要对其进行更改,使其同时使用\n\r 作为输入记录分隔符。

有什么想法吗?

【问题讨论】:

  • Nitpick:你 use Term::ANSIColor 但你实际上并没有使用 Term::ANSIColor.

标签: perl


【解决方案1】:

从文件中读取有四种方法:

  • 一次一个字符:getc
  • 一次一行:readline$/ = $terminator;
  • 一次一个块:readreadline$/ = \$length;
  • 数据到达时:sysread

getc 可以,但我会使用更高效的sysread

perl -we'
   sub make_iter {
      my ($fh) = @_;

      my $buf = "";
      my $eof = 0;

      return sub {
         return if $eof;

         while (1) {
            return $1 if $buf =~ s/^([^\r\n]*[\r\n])//;

            my $rv = sysread(STDIN, $buf, 64*1024, length($buf));
            if (!$rv) {
               $eof = 1;
               die $! if !defined($rv);
               return $buf if length($buf);
               return;
            }
         }
      };
   }

   binmode(STDIN);
   binmode(STDOUT);
   $| = 1;

   my $iter = make_iter(\*STDIN);
   while (my ($line) = $iter->()) {
      $line = "\e[1;91m" . $line . "\e[0m" if $line =~ /ERROR/i;
      print($line);
   }
'

【讨论】:

    【解决方案2】:

    只需插入替换管段:

    ... | perl -pe 's/\r/\n/g' | ...

    RUN.SH ${@} 2>&1 | perl -pe 's/\r/\n/g' | perl -M"Term::ANSIColor" -wnl -e '
    m/ERROR/i and print "\e[1;91m", "$_", "\e[0m" 
    or print;'
    

    测试:

    ivr@linux-e8sg:~> echo -e 'a\nb\rc\n'
    a
    c
    
    ivr@linux-e8sg:~> echo -e 'a\nb\rc\n'  | perl -pe 's/\r/\n/g'
    a
    b
    c
    

    【讨论】:

    • 这里有一个问题!例如,当JOB.SH 输出是一个计时器(这就是它不打印新行的原因)时,我会在新行上打印很多计时器,而不是在同一行上
    • 在收到换行符之前仍然会阻塞。
    【解决方案3】:

    哦,天哪,有很多不正确的伟大而神奇的脚本。

    '$INPUT_RECORD_SEPARATOR' 更改默认值为 '\n' 您可以在 perl 脚本本身中将其更改为您需要的内容。

    您可以在perl special variables 阅读更多内容,使用网络浏览器查找并搜索“INPUT_RECORD_SEPARATOR”

    【讨论】:

    • 猎物告诉如何将其更改为“CR 或 LF”!
    • 这不能回答问题。您可以将$/ 设置为\n \r,但不能同时设置。
    • 您可以将其设置为任何您想要的“\n\n”“啤酒”等。答案中显然缺乏 perl 知识,但无论如何。我也测试了自己的,我用很少的代码就达到了相同的结果。
    • 我们不知道?然后教育我们。如果遇到 CR 或 LF,哪个值将导致 <> 返回。
    • 如果你测试过,也许你应该展示你使用的代码。
    猜你喜欢
    • 2012-07-17
    • 2012-08-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多