查找与模式匹配的每一行,但仅打印其上方的行

查找与模式匹配的每一行,但仅打印其上方的行

我需要找到一个字符串并需要打印它上面的行。

case1:同一行不会有多个匹配模式

即)考虑一个文件包含

$cat > para
returns between the paragaraphs
italic or bold    
quotes by placing
italic

在这里我需要找到斜体,并且我需要得到如下输出

在段落之间返回
通过放置报价

我怎样才能得到这样的输出?

答案1

切勿在匹配文本的上下文中使用“模式”一词,因为它非常不明确,始终至少使用“字符串”或“正则表达式”和“部分”或“完整”,无论您指的是哪种匹配。看https://stackoverflow.com/q/65621325/1745001了解更多信息。

我们无法从您的问题中得知您想要什么类型的匹配,因此这里有一些示例,所有这些示例都会根据发布的示例输入生成发布的预期输出,并且其中任何/所有可能完全不符合操作员的需求:

部分行正则表达式匹配:

$ awk '/italic/{print p} {p=$0}' file
returns between the paragaraphs
quotes by placing

部分线串匹配:

$ awk 'index($0,"italic"){print p} {p=$0}' file
returns between the paragaraphs
quotes by placing

部分字段正则表达式匹配:

$ awk '{for (i=1; i<=NF; i++) if ($i ~ /italic/) print p} {p=$0}' file
returns between the paragaraphs
quotes by placing

部分字段字符串匹配:

$ awk '{for (i=1; i<=NF; i++) if (index($i,"italic")) print p} {p=$0}' file
returns between the paragaraphs
quotes by placing

全字段正则表达式匹配

a) 使用 GNU awk 作为字边界):

$ awk '/\<italic\>/{print p} {p=$0}' file
returns between the paragaraphs
quotes by placing

b) 使用任何 awk:

$ awk '/(^|[[:space:]])italic([[:space:]]|$)/{print p} {p=$0}' file
returns between the paragaraphs
quotes by placing

全字段字符串匹配:

a)使用循环:

$ awk '{for (i=1; i<=NF; i++) if ($i == "italic") print p} {p=$0}' file
returns between the paragaraphs
quotes by placing

b) 没有循环和正则表达式辅助:

$ awk 's=index($i,"italic") && (substr($0,s-1,1) ~ /^|[[:space:]]/) && (substr($0,s+length("italic"),1) ~ /[[:space:]]|$/){print p} {p=$0}' file
returns between the paragaraphs
quotes by placing

以上所有内容显然都会根据您发布的示例输入产生预期的输出,并且根据您对字符串与正则表达式以及完全匹配与部分匹配的要求,如果输入不同,所有上述输出都会失败。

答案2

如果该模式不能出现在连续的行上,您可以简单地运行

sed '$!N;/.*\n.*PATTERN.*/P;D' infile

我有在这里解释怎么了NP;D循环工作。不同之处在于,这里仅当第二行匹配时才打印模式空间中的第一行,否则将其删除。


如果该模式可以出现在连续的行上,则上述解决方案将打印匹配的行(如果后面跟着另一行匹配的行)。
要忽略连续匹配,请添加第二个条件,仅当不匹配时才打印模式空间中的第一行:

sed '$!N;/.*\n.*PATTERN.*/{/.*PATTERN.*\n.*/!P;};D' infile

另一种方法是使用保持缓冲区。
如果你想忽略连续的匹配:

sed '/PATTERN/!{              # if line doesn't match PATTERN
h                             # copy pattern space content over the hold buffer
d                             # delete pattern space
}
//{                           # if line matches PATTERN
x                             # exchange pattern space with hold space
//d                           # if line matches PATTERN delete it
}' infile

或者,在一行中

sed '/PATTERN/!{h;d;};//{x;//d;}' infile

如果您不想忽略连续的匹配项:

sed '/PATTERN/!{              # if line doesn't match PATTERN
h                             # copy pattern space content over the hold buffer
d                             # delete pattern space
}
//x                           # if line matches PATTERN exchange buffers
' infile 

或者,在一行中

sed '/PATTERN/!{h;d;};//x' infile

但请记住,如果文件中的第一行匹配,则使用保留缓冲区的两个解决方案将打印前导空行。如果这是一个问题,只需1d在第一次//检查后添加 例如
sed '/PATTERN/!{h;d;};//{1d;x;//d;}'和 sed'/PATTERN/!{h;d;};//{1d;x;}'

答案3

使用grep, 然后sed:

grep --no-group-separator -B 1 "italic" <yourfilename> | sed -n 1~2p`

解释:

grep手动的:

-B num
--before-context=num
Print num lines of leading context before matching lines

--no-group-separator
When -A, -B or -C are in use, do not print a separator between groups of lines.

sed:

选择两行中的第一行。我们还可以输入 sed -n 1~5p 来选择五个中的第一个。

相关内容