【问题标题】:Linux shell: change Perl code to linux shell, grep line by lineLinux shell:将Perl代码改为linux shell,逐行grep
【发布时间】:2014-12-26 09:27:33
【问题描述】:

下面的代码是 Perl 脚本,来自 hostlog 的带有 'Stage' 的 grep 行。然后逐行匹配正则表达式的内容,如果找到将计数加1:

$command = 'grep \'Stage \' '. $hostlog;
@stage_info = qx($command);
foreach (@stage_info) {
    if ( /Stage\s(\d+)\s(.*)/ ) {
        $stage_number = $stage_number+1;
    }
}

那么如何在 linux shell 中做到这一点?根据我的测试,我们不能逐行循环,因为里面有空间。

【问题讨论】:

  • En。行。在 Perl 中,我们可以得到匹配的部分 $1 和 $2。那么除了数字之外,如何在 linux shell 中获取这些值?谢谢!
  • 如果您需要匹配部分的详细信息,您必须使用 sed 重新格式化文件。或者,也许您可​​以使用 shell 表达式将行分解成您需要的部分。
  • 索要代码翻译显然不在 SO 上。发布您的 shell 代码,人们肯定会愿意帮助您解决具体问题,但他们不会为您编写。

标签: perl shell grep


【解决方案1】:

那是一段可怕的 Perl 代码。原因如下:

  1. 您似乎没有使用use strict; use warnings;。这是一个巨大的错误,不会阻止错误,只会隐藏错误。
  2. 使用qx() grep 文件中的行是完全多余的事情,因为这是Perl 本身最擅长的。 “淘汰”这样的过程通常会减慢您的程序速度。
  3. 使用一些空格使您的代码可读。这很难阅读,而且看起来比实际复杂。
  4. 您在正则表达式中使用括号来捕获字符串,但您从不使用这些字符串。
  5. 回复:$stage_number=$stage_number+1,见第 3 点。此外,这可以写成$stage_number++。使用++ 运算符将使您的代码更清晰,防止出现未初始化的警告,并节省您的打字时间。

你的代码应该是这样的:

use strict;
use warnings;

open my $fh, "<", $hostlog or die "Cannot open $hostlog for reading: $!";
while (<$fh>) {
    if (/Stage\s\d+/) {
        $stage_number++;
    }
}

【讨论】:

  • 虽然这些评论是有效的批评,但这并不能回答提出的问题。另外,错误的正则表达式。
  • 不,这不是“错误”。正如我所解释的,捕获任何内容都没有意义,因此不需要括号,因此无需添加匹配空格和任何内容的 \s.* 部分。此外,是的,它确实回答了这个问题,在更大的方面是可以实际使用并因此被翻译的 Perl 代码。更大的答案是使用 shell 脚本没有任何好处。
【解决方案2】:

您没有对内部捕获做任何事情,那何必呢?您可以使用grep 完成所有操作:

$ stage_number=$(grep -E 'Stage\s\d+\s' | wc -l)

这是使用扩展的正则表达式。我相信 GNU 版本在没有 -E 参数的情况下接受这些,而在 Solaris 中,即使是 egrep 命令也可能不太允许这个正则表达式。

如果你还有其他事情要做,你必须在你的问题中解释它。

【讨论】:

  • 幸运的是,他使用的是 linux,所以使用的是 GNU grep。 grep -Eegrep 相同 grep -c 将直接返回计数而不需要 wc -l
  • 哦,我忘了-c 参数。这是grep所有版本的标准。
【解决方案3】:

如果我正确理解了这个问题,你应该可以在 shell 中做到这一点:

while read; do
    if echo ${REPLY} | grep -q -P "'Stage' "; then
        # Do what you need to do
    fi
done < test.log

请注意,如果您的 grep 命令支持 -P 选项,则您可以按原样使用 Perl 正则表达式进行第二次测试。

【讨论】:

    【解决方案4】:

    差不多了。 bash 没有多个数字的表达式。

    #!/bin/bash 
    
    command=( grep 'Stage ' "$hostlog" )
    
    while read line 
    do
      [ "$line" != "${line/Stage [0-9]/}" ] && (( ++stage_number ))
    done < <( "${command[@]}" )
    

    另一方面,考虑到 perl 脚本的功能而不是它执行的操作,整个事情可以重写为

    (( stage_number += ` grep -c 'Stage \d\+\s' "$hostlog" ` ))
    

    或者这个

    stage_number=` grep -c 'Stage \d\+\s' "$hostlog" `
    

    如果在原始 perl 中,stage_number 未初始化,或者初始化为 0。

    【讨论】:

    • 谢谢,这几乎是我需要的。但似乎在
    • 好的,我已经实际测试了这些版本,现在它们应该适合你。不要忘记将 hostlog 设置为或使用适当的文件名替换 $hostlog。
    猜你喜欢
    • 2013-11-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多