Grep 在文件中查找文本并打印前面 3 行的文本

Grep 在文件中查找文本并打印前面 3 行的文本

我有一个文件,并将在该文件中查找多个文件名。搜索文本示例intl_reg.jcl。找到它后,我需要获取其上方 3 行的文本。例如,下面是文件中的 4 行。描述“有余额的注册国际学生”之前的文字始终是 CHOICE,后面是描述。

CHOICE List registered international students with balances   
SHORTCUT 8  
PROCESS CHDIR /d3/locban/arsys  
PROCESS CMD ksh /d3/locban/arsys/intl_reg.jcl

我需要 grep 命令来列出它,如下所示:

intl_reg.jcl  registered international students with balances

答案1

使用(以前称为 Perl_6)

~$ raku -e 'my @a; for lines() { 
            if @a.elems == 4 { @a.push($_); @a.shift } 
            elsif @a.elems < 4 { @a.push($_) }; 
            if .match( /intl_reg\.jcl/ ) and @a.elems == 4 {
            say $<>.Str, @a[0].split( /<?after List>/ ).[1] }; 
            };' file

简而言之,@a声明一个数组并lines从命令行读入。输入被push添加到@a数组中,直到elems等于 4,然后第一个元素被shift删除以保持最大大小为 4 个元素。

如果match发现and数组包含 4 个元素,则$<>打印匹配变量($<>与 相同$/),然后打印 3 行之前记录的行,以适当地split返回所需的字符串。

输入示例:

A CHOICE List registered international students with balances   
A SHORTCUT 8  
A PROCESS CHDIR /d3/locban/arsys  
A PROCESS CMD ksh /d3/locban/arsys/intl_reg.jcl
B CHOICE List registered international students with balances   
B SHORTCUT 8  
B PROCESS CHDIR /d3/locban/arsys  
B PROCESS CMD ksh /d3/locban/arsys/intl_reg.jcl

示例输出:

intl_reg.jcl registered international students with balances   
intl_reg.jcl registered international students with balances  

https://raku.org

答案2

以下awk程序可以工作。

选项 1:双通道

awk -v d=3 -v s="intl_reg.jcl" '(NR==FNR) && index($0,s){i=FNR;nextfile} 
                                FNR==(i-d){printf "%s\t%s\n",s,$0; exit}' input.txt input.txt

此处,输入文件被指定两次,以便对其进行两次处理。要搜索的字符串作为awk变量传递s,距离作为awk变量传递d

  • 在第一遍中,NR全局行计数器 等于FNR每个文件行计数器,每行都会检查字符串是否出现。如果找到,行号将存储在变量中i,并且执行立即跳到下一个文件(=同一文件的下一次迭代)。
  • 在第二遍中,程序检查当前行号是否d小于先前识别的模式出现次数(存储在i.当遇到该行时,它将与搜索字符串一起打印,并且程序终止(以免闲置地循环文件的其余部分。

选项 2:单程

为了加速该过程,并且对于无法重新访问文件的情况(例如,因为它是管道),也可以使用带有缓冲的单通道解决方案。在这种情况下,需要一定长度的 FIFO 缓冲区,这意味着如果太大则d不切实际(但很少会成为问题):d

awk -v d=3 -v s="intl_reg.jcl" 'FNR>1{for (j=d;j>0;j--) {buf[j]=buf[j-1]}; buf[0]=$0}
                            FNR>d && match($0,s) {printf "%s\t%s\n",s,buf[d];exit}' input.txt

buf这将连续用最后几行填充缓冲区d+1,其中缓冲区内容在每个新行处“向上移动”,并且当前行始终位于buf[0].一旦找到搜索字符串,它将打印 的内容buf[d],即d当前行之前的行。同样,由于性能原因,程序会立即终止。

答案3

match=intl_reg.jcl
tac {file} |
    sed -n "/$match/ { n; n; n; s/^CHOICE/$match/p }"

确保既不$match包含/也不包含正则表达式运算符。 (请注意,这.实际上是一个通配符,因此请立即打破此规则。这对您来说可能是问题,也可能不是问题。)

答案4

使用任何 awk:

$ awk -v t='intl_reg.jcl' '{a[NR%4]=$0} index($0,t){$0=a[(NR-3)%4]; $1=$2=""; print t $0}' file
intl_reg.jcl  registered international students with balances

相关内容