简洁的方式将所有行打印到与给定模式匹配的最后一行

Æva*_*son 7 linux shell perl tail

我试图找到一个简洁的shell单行程序,它会在文件中提供所有行,直到某种模式.

用例是将所有行转储到日志文件中,直到我发现一些标记表明服务器已重新启动.

这是一种愚蠢的shell专用方式:

tail_file_to_pattern() {
    pattern=$1
    file=$2

    tail -n$((1 + $(wc -l $file | cut -d' ' -f1) - $(grep -E -n "$pattern" $file | tail -n 1 | cut -d ':' -f1))) $file
}
Run Code Online (Sandbox Code Playgroud)

在stdin上获取文件的稍微更可靠的Perl方式:

perl -we '
    push @lines => $_ while <STDIN>;
    my $pattern = $ARGV[0];
    END {
        my $last_match = 0;
        for (my $i = @lines; $i--;) {
            $last_match = $i and last if $lines[$i] =~ /$pattern/;
        }
        print @lines[$last_match..$#lines];
    }
'
Run Code Online (Sandbox Code Playgroud)

当然,你可以更有效地打开文件,寻找到最后并回头找到匹配的行.

第一次出现时很容易打印所有内容,例如:

sed -n '/PATTERN/,$p'
Run Code Online (Sandbox Code Playgroud)

但是我还没有想出一种方法来打印最后一次出现的所有东西 .

Rob*_*vis 6

这是一个仅限sed的解决方案.要从匹配的最后一行$file 开始打印每一行$pattern:

sed -e "H;/${pattern}/h" -e '$g;$!d' $file
Run Code Online (Sandbox Code Playgroud)

请注意,与您的示例一样,只有在文件包含模式时才能正常工作.否则,它输出整个文件.

以下是括号中的sed命令:它的功能细分:

  • [H]将每一行附加到sed的"保留空间",但不要将其回显到stdout [d].
  • 当我们遇到模式时,[h]扔掉保持空间并从匹配线开始.
  • 当我们到达文件的末尾时,将保留空间复制到模式空间[g],以便它将回显到stdout.

另请注意,对于非常大的文件,它可能会变慢,因为任何单通道解决方案都需要在内存中保留一堆行.


Joh*_*nck 3

我建议简化你的 shell 脚本:

tail -n +$(grep -En "$pattern" "$file" | tail -1 | cut -d: -f1) "$file"
Run Code Online (Sandbox Code Playgroud)

它更加简洁,因为它:

  • 使用 tail 的+选项从给定行打印到末尾,而不必计算从那里到末尾的距离。
  • 使用更简洁的方式来表达命令行选项。

它通过引用 $file 修复了一个错误(因此它将适用于名称包含空格的文件)。