我需要找到一个字符串并需要打印它上面的行。
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
我有在这里解释怎么了N
;P
;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 来选择五个中的第一个。