grep的-A -B -C开关是否有其他选择(在之前和之后打印几行)?


10
grep -A 2 -B 3 

在grep字符串之后打印2行,在grep字符串之前打印3行。

grep -C 3

在前面打印3行,在后面打印3行

不幸的是,grep我正在使用的不支持这些选项。有没有其他可用的命令或脚本来模拟此情况?使用sed/ awk/ perl/ shell脚本?


+1我不知道有没有-C切换。
Lazer

1
安装GNU的grep。更一般而言,当一台新的Sun机器到达这里时,设置的第一步就是有人所说的GNU > /usr/local。GNU程序具有许多非常有用的扩展,旨在避免任意限制(但您确实付出了巨额的代价,有时还付出了巨大的性能)。许多专有系统具有使用GNU和其他工具的“非官方”软件包存储库。即使由供应商管理,“合作伙伴”也不会告诉您这些信息
vonbrand

Answers:


6

一种比较丑陋的方法是

grep -v pattern file >file.tmp; diff -c file.tmp file

或替换-c-C NUM用于NUM上下文的行。不过,它将产生额外的输出。(如果您diff支持-u/ -U NUM,它将更加干净。)

如果您diff没有-c/ -C/ -u,仍然可以使用,但是它们很难看。另一方面,diff甚至不支持的系统也-c可能没有Perl。


这很酷,就像魅力一样工作,尽管我必须对此使用-bitw选项,以使其适用于Windows生成的文件。
Prashant Bhate

您可以将stdin发送到diff,并跳过以下临时选项:grep -v pattern file | diff -c - file
Cascabel

5

ACK只需要Perl和包括-A-B-C选项的工作如grep的。它使用Perl的regex语法而不是grep的语法,并且它选择文件进行搜索的方式完全不同。您可能需要-f在使用该选项时尝试使用该选项(该选项会打印出将搜索的文件,而无需实际搜索任何内容)。

它可以作为单个脚本安装,不需要非核心模块。只需将其放入您的~/bin目录(或您具有写访问权限的PATH上的其他任何位置)中,并确保它是chmod可执行文件。


它的生产包装盒,不幸的是,我没有足够的特权来安装任何东西,但是我不能冒险,但是,感谢您为我提供的技巧,我将安装它并尝试在家用笔记本电脑上使用
Prashant Bhate

@Prashant,您不需要root用户即可安装ack使用。
cjm 2011年

是的,但是我仍然不能在那里使用它,尽管它可以确保该脚本永远存在于我的〜/ bin中:)
Prashant Bhate

@Prashant:你为什么不能使用它?这只是一个perl脚本。
直觉

1
它的PRODUCTION框需要经过特殊权限批准才能进行任何操作。一切都出了问题;)并且它不值得:)
Prashant Bhate

5

这个简单的perl脚本grep -A在某种程度上模拟

#!/usr/bin/perl

$pattern=shift; #patthern to search
$lines=shift; # number of lines to print

$n = 0;
while (<>) {
  $n = $lines if /$pattern/; # reset counting
  if ($n) { print; $n-- } # print if within
  $n = 0 if eof; # don't leak across file boundaries
}

请注意,您可以添加用法声明,以使脚本可读和可用;)

USAGE:    $./grep-A.pl <pattern> <numLines> <filename> 

尼斯,我需要运行哪个版本的perl?
Prashant Bhate

我使用v5.10.1,我猜这些天Perl 5相当普遍。
Vijay Anant

ya,它的5.8.8很好用,但是我需要一个脚本来执行-B的功能
Prashant Bhate

好。不过,我将切换参数的顺序。grep-A 3 foo看起来比grep-A foo 3。:-)
musiphil

3

您可以只安装GNU grepAck(用Perl编写,可以理解GNU grep的许多选项以及更多内容)。

如果您喜欢使用标准工具和一些脚本,那么这是一个awk脚本,它模仿GNU grep -A-Boptions 的行为。最少测试。

#!/bin/sh
# grep-ac: a grep-like awk script
# Arguments: pattern = awk regexp to search for
#            before = number of lines to print before a match
#            after = number of lines to print after a match
{ "exec" "awk" "-f" "$0" "$@"; }
# The array h contains the history of lines that haven't been printed
# but are eligible for being "before" lines.
# The variable until contains the number of the last "after" line to print.
match($0, pattern) {   # the current line matches
    for (i in h) {
        print h[i];    # print each remaining before line
        delete h[i];   # delete each line as it's printed
    }
    until=NR+after;    # record the last after line to print
}
{
    if (NR<=until) print $0;    # from a match to its last after line: print
    else h[NR]=$0;              # after that: save in history
    delete h[NR-before];        # remove line too old to be a before line
}
END {exit !until}               # exit status: 0 if there was a match, else 1

运行它grep-ac -vpattern=PATTERN -vbefore=NBEFORE -vafter=NAFTER,其中PATTERN是搜索(一个图案扩展正则表达式与几个AWK增补),并NBEFORENAFTER有线的数目之前和匹配分别(默认为0)后进行打印。例:

<input_file grep-ac -vbefore=2 -vpattern='foo *bar'

任何将数据存储在数组中的解决方案都是毫无疑问的……正如我之前提到的,文件大小非常庞大,并且可能会溢出。另外,在该系统上,awk不允许文件大小超过3000个字节。
Prashant Bhate

2
@Prashant:我不理解您的反对意见。该脚本将删除不符合条件的行。它使用的内存没有超出给定要求所固有的内存,除了awk的开销可能比专用程序高(但比Perl还要少)。文件的总大小是完全无关的。
吉尔(Gilles)'所以

2
{ "exec" "awk" "-f" "$0" "$@"; }:绕过shebang行解析中的限制的一种非常巧妙的方法。
dubiousjim 2012年

2

事实证明,模拟-B是非常棘手的,因为当您有彼此直接匹配的匹配行时出现的问题。这几乎不允许使用任何类型的单次通过文件扫描。

我在尝试以下近似时意识到了这一点:

perl -pe 'if(/search_term/) {print foreach @A; print ">"; $B=4}; shift @A if push(@A, $_)>7; $_ = "" unless ($B-- > 0);' target_file

这将大致像grep -A7 -B3一样正常工作,并在第一段中进行了说明。

此问题的另一种(也是单文件)解决方案是使用perl来馈送sed命令字符串:

sed -n `perl -pe '$_=(/search_term/?sprintf("%d,%dp;", $.-3,$.+4):"")' file` file

相当宽大的oneliner,但是,此文件非常大,因此在这种情况下将行推入数组是一个坏主意,不是吗?
Prashant Bhate

shift @A if push(@A,$_)>7;位仅保留最大大小为7的数组。(这是您的-A参数)。第二个选项可以保留一个非常小的文件(只需在没有sed外层的情况下运行perl即可查看在那里生成的内容),但是它确实读取了两次文件。
2011年

0

使用,sed您可以首先获取匹配行的行号,在while循环中递减并递增给定的行号,然后用于sed -n "n1,n2p"打印前导(n1)和尾随(n2)上下文的行(类似于seduser455建议的替代方法)。但是,许多读取过程可能会导致性能下降。

ed可以直接引用匹配行的上一行和下一行,但是如果指定的行范围不存在,则失败;例如,匹配行是第2行,但应打印5条预匹配行。使用ed,因此需要添加的在开始和结束时(空的)线的适当数量。(但是,对于大文件ed可能不是正确的工具,请参阅:bfs-大文件扫描仪)。

# sample code to match lines with number 5 plus previous & following line
# (using Bash)
printf '%s\n' {1..20} > num.txt

# sed
sed -n '/5/=' num.txt | while read num; do
   n1=$((num - 1))
   n2=$((num + 1))
   [[ $n1 -lt 1 ]] && n1=1
   sed -n "${n1},${n2}p" num.txt
   echo --
done | sed -e '${/^--$/d;}'

# ed
cat <<-'EOF' | ed -s num.txt | sed -e $'N;N;a\\\n--' | sed -e '${/^--$/d;}'
H
0i
beginning: added line one
.
$a
end: added line one
.
,g/5/km\
'm-1,'m+1p
q
EOF
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.