如何搜索包含以下文本的文件,并且仅重定向输出,其中第三行有“Msg 208”,后跟“# name not found”?
文件文本:
[
DBCC upgrade_object: DEFAULT dc_1527463 upgraded successfully.
DBCC upgrade_object: Upgrading PROCEDURE tran_33
DBCC upgrade_object: There's a difference between the objectname tran_33 and the name tran_33 used in syscomments.
DBCC upgrade_object: Maybe the object was renamed using sp_rename.
Msg 208, Level 16, State 1:
Server 'DEV_RP', Procedure 'dbo.itxxn_33', Line 40:
#old_33 not found. Specify owner.objectname or use sp_help to check whether the object exists (sp_help may produce lots of output).
Msg 207, Level 16, State 4:
Server 'DEV_RP', Line 3:
Invalid column name 'eryCmt'.
Msg 208, Level 16, State 1:
Server 'DEV_RP', Procedure 'dbo.yftran_33', Line 40:
bat not found. Specify owner.objectname or use sp_help to check whether the object exists (sp_help may produce lots of output).
Msg 208, Level 16, State 1:
Server 'DEV_RP', Procedure 'dbo.yftran_33', Line 40:
#wbat not found. Specify owner.objectname or use sp_help to check whether the object exists (sp_help may produce lots of output).
]
示例 - 有效且应在输出中捕获:
{
Msg 208, Level 16, State 1:
Server 'DEV_RP', Procedure 'dbo.itxxn_33', Line 40:
#old_33 not found. Specify owner.objectname or use sp_help to check whether the object exists
}
示例 - 无效且不应在输出中捕获:
{
Msg 208, Level 16, State 1:
Server 'DEV_RP', Procedure 'dbo.yftran_33', Line 40:
bat not found. Specify owner.objectname or use sp_help to check whether the object exists (sp_help may produce lots of output).
}
答案1
假设空行是伪造的编辑工件:
注意:input2.txt
是示例输入的编辑副本,删除了多余的换行符。
$ sed -E -e 's/^(Msg |\])/\n\1/; s/\[/[\n/' input2.txt |
perl -00 -l -n -e 'print if /^Msg 208.*^#.*not found/ms'
Msg 208, Level 16, State 1:
Server 'DEV_RP', Procedure 'dbo.itxxn_33', Line 40:
#old_33 not found. Specify owner.objectname or use sp_help to check whether the object exists (sp_help may produce lots of output).
Msg 208, Level 16, State 1:
Server 'DEV_RP', Procedure 'dbo.yftran_33', Line 40:
#wbat not found. Specify owner.objectname or use sp_help to check whether the object exists (sp_help may produce lots of output).
这用于sed
将输入转换为以 或 的每个实例开头的每一行的Msg
段落。然后将的输出通过管道输送到以段落模式 ( )读取输入 ( ) 并打印该段落[
]
sed
perl
-n
-00
当且仅当它匹配正则表达式^Msg 208.*^#.*not found
(使用 perl 的m
修饰符将每个段落视为多行字符串,并使用s
修饰符来允许.
匹配换行符)。
“段落”是由一个或多个换行符分隔的一行或多行文本。
有关 perl 命令行选项的更多信息,请参阅man perlrun
,有关 perl 正则表达式的更多信息,请参阅man perlre
。有关在 Perl 脚本中使用正则表达式的教程,请参阅man perlretut
。
从man perlre
:
m
将匹配的字符串视为多行。也就是说,将 and 从匹配字符串第一行的开头和最后一行的结尾更改^
为$
匹配字符串中每行的开头和结尾。
s
将字符串视为单行。也就是说,更改.
为匹配任何字符,甚至是换行符,通常它不会匹配。一起使用时,
/ms
它们可以让.
匹配任何字符,同时仍然允许^
和$
分别匹配字符串中换行符之后和之前的字符。
顺便说一句,这本来可以完全在 Perl 中完成,但将sed
输入转换为 Perl 的段落模式可以轻松处理的内容会更简单、更容易、更快。
另外顺便说一句,如果您希望输出中包含花括号,请将行更改print if ...
为print "{\n$_\n}\n" if ...
打印与您最初要求相反的内容(即打印包含以Msg
该开头的行的段落不包含^Msg 208.*^#.*not found
)将if ...
语句更改为if (/^Msg /ms && ! /^Msg 208.*^#.*not found/ms)
。即(带有额外的换行和缩进以提高可读性):
sed -E -e 's/^(Msg |\])/\n\1/; s/\[/[\n/' input2.txt |
perl -00 -l -n -e 'print if (/^Msg /ms &&
! /^Msg 208.*^#.*not found/ms)'
答案2
在每个 Unix 机器上的任何 shell 中使用任何 awk:
$ cat tst.awk
/^#[^ ]+ not found/ && (p2 ~ /^Msg 208,/) {
print "{" ORS p2 ORS p1 ORS $0 ORS "}"
}
{ p2=p1; p1=$0 }
$ awk -f tst.awk file
{
Msg 208, Level 16, State 1:
Server 'DEV_RP', Procedure 'dbo.itxxn_33', Line 40:
#old_33 not found. Specify owner.objectname or use sp_help to check whether the object exists (sp_help may produce lots of output).
}
{
Msg 208, Level 16, State 1:
Server 'DEV_RP', Procedure 'dbo.yftran_33', Line 40:
#wbat not found. Specify owner.objectname or use sp_help to check whether the object exists (sp_help may produce lots of output).
}
上面假设问题中的预期输出是错误的,并且包含的块#wbat
应该包含在输出中,并且进一步假设每个输出块应该被包装在其中,{...}
如果这是一个错误的假设,则更改是微不足道的。
答案3
您可以像这样一次性提取这些行sed
:
sed -n '1N;N;/Msg 208.*\n.*\n#[[:alnum:]_]* not found/p;D'
-n
抑制正常输出的选项N;D
始终一起处理两条线的方案;1N
在文件开头添加第三行- 该模式
Msg 208.*\n.*\n#[[:alnum:]_]* not found
描述了您想要p
打印的三元组
如果你想用大括号括住每场比赛,请这样做:
sed -n '1N;N;h;s/Msg 208.*\(\n\).*\n#[[:alnum:]_]* not found.*/{\1&\1}/p;g;D'
ubstitute命令s
添加大括号和额外的换行符(被捕获\(\n\)
并重用,\1
因为\n
在替换中未定义)。当然,我们需要将原来的内容保存在h
旧空间中,然后用g
.