sds*_*sds 5 grep sed awk perl text-processing
我想找到相邻的匹配行,例如,如果模式匹配是
$ grep -n pattern file1 file2 file3
file1:10: ...
file2:100: ...
file2:1000: ...
file2:1001: ...
file3:1: ...
file3:123: ...
Run Code Online (Sandbox Code Playgroud)
我想找到中间的两个匹配项:
file2:1000: ...
file2:1001: ...
Run Code Online (Sandbox Code Playgroud)
但不是前两个和后两个。
我将使用与 thrig 相同的测试文件:
$ cat file
a
pat 1
pat 2
b
pat 3
Run Code Online (Sandbox Code Playgroud)
这是 awk 的解决方案:
$ awk '/pat/ && last {print last; print} {last=""} /pat/{last=$0}' file
pat 1
pat 2
Run Code Online (Sandbox Code Playgroud)
awk
隐式循环文件中的每一行。该程序使用一个变量 ,last
如果它与 regex 匹配,则该变量包含最后一行pat
。否则,它包含空字符串。
/pat/ && last {print last; print}
如果pat
匹配此行且上一行 ,last
也匹配,则打印这两行。
{last=""}
替换last
为空字符串
/pat/ {last=$0}
如果该行匹配pat
,则设置last
为该行。这样,当我们处理下一行时,它就可用了。
让我们考虑这个扩展的测试文件:
$ cat file2
a
pat 1
pat 2
b
pat 3
c
pat 4
pat 5
pat 6
d
Run Code Online (Sandbox Code Playgroud)
与上面的解决方案不同,此代码将三个连续的匹配行视为一组要打印:
$ awk '/pat/{f++; if (f==2) print last; if (f>=2) print; last=$0; next} {f=0}' file2
pat 1
pat 2
pat 4
pat 5
pat 6
Run Code Online (Sandbox Code Playgroud)
此代码使用两个变量。和以前一样,last
是上一行。此外,还f
计算连续匹配的次数。因此,当f
为 2 或更大时,我们打印匹配的行。
为了模拟grep
问题中显示的输出,此版本在每个匹配行之前打印文件名和行号:
$ awk 'FNR==1{f=0} /pat/{f++; if (f==2) printf "%s:%s:%s\n",FILENAME,FNR-1,last; if (f>=2) printf "%s:%s:%s\n",FILENAME,FNR,$0; last=$0; next} {f=0}' file file2
file:2:pat 1
file:3:pat 2
file2:2:pat 1
file2:3:pat 2
file2:7:pat 4
file2:8:pat 5
file2:9:pat 6
Run Code Online (Sandbox Code Playgroud)
awk 的 FILENAME 变量提供文件名,awk 的 FILENAME 变量FNR
提供文件内的行号。
在每个文件的开头,FNR==1
我们重置f
为零。这可以防止一个文件的最后一行被视为与下一个文件的第一行连续。
对于那些喜欢将代码分布在多行中的人来说,上面的代码如下所示:
awk '
FNR==1{f=0}
/pat/ {f++
if (f==2) printf "%s:%s:%s\n",FILENAME,FNR-1,last
if (f>=2) printf "%s:%s:%s\n",FILENAME,FNR,$0
last=$0
next
}
{f=0}
' file file2
Run Code Online (Sandbox Code Playgroud)