grep 访问多行,查找两个模式之间的所有单词
Posted
技术标签:
【中文标题】grep 访问多行,查找两个模式之间的所有单词【英文标题】:Grep Access Multiple lines, find all words between two patterns 【发布时间】:2012-10-06 18:21:37 【问题描述】:在扫描文本文件和查找两种模式之间的所有单词时需要帮助。比如说如果我们有一个 .sql 文件,需要扫描并找到 from' 和 'where' 之间的所有单词。 Grep 一次只能扫描 1 行。对于这个要求,最好使用的 unix 脚本是什么? sed、awk有这些功能吗?非常感谢您指出任何示例。
【问题讨论】:
你能粘贴一个示例 sql 内容吗?例如有多少来自...在您的文件中的哪里?是否存在“来自”和“哪里”在同一行的情况?所有这些都使提取逻辑不同。 这个答案也可能适用:***.com/a/48022994/2026975 【参考方案1】:Sed 有这个:
sed -n -e '/from/,/where/ p' file.sql
打印带有from
的行和带有where
的行之间的所有行。
对于可以包含同时具有 from 和 where 的行的内容:
#!/bin/sed -nf
/from.*where/
s/.*\(from.*where\).*/\1/p
d
/from/
: next
N
/where/
s/^[^\n]*\(from.*where\)[^\n]*/\1/p
d
$! b next
这个(写成 sed 脚本)稍微复杂一些,我会尽量解释细节。
第一行在包含from
和where
的行上执行。如果一行与该模式匹配,则执行两个命令。我们使用s
替代命令仅提取 from 和 where 之间的部分(包括 from 和 where)。该命令中的p
后缀打印该行。 delete 命令清除模式空间(工作缓冲区),加载下一行并重新启动脚本。
当找到包含from
的行时,第二个命令开始执行一系列命令(由大括号分组)。基本上,这些命令形成了一个循环,它将不断将输入中的行追加到模式空间中,直到找到带有 where
的行或直到我们到达最后一行。
:
“命令”创建一个标签,脚本中的一个标记,允许我们在需要时“跳转”回来。 N
命令从输入中读取一行,并将其附加到模式空间(用换行符分隔行)。
当找到where
时,我们可以打印出模式空间的内容,但首先我们必须用替换命令清理它。它类似于之前使用的那个,但是我们现在用[^\n]*
替换前导和尾随.*
,这告诉sed 只匹配非换行符,有效地匹配第一行中的from 和最后一行中的where线。然后d
命令清除模式空间并在下一行重新启动脚本。
b
命令将跳转到一个标签,在我们的例子中是标签next
。但是,$!
地址表示它不应该在最后一行执行,这样我们就可以离开循环。以这种方式离开循环时,我们没有找到相应的where
,因此您可能不想打印它。
但是请注意,这有一些缺点。以下情况将无法按预期处理:
from ... where ... from
from ... from
where
from
where ... where
from
from
where
where
处理这些情况需要更多代码。
希望这会有所帮助 =)
【讨论】:
谢谢,帮我省了一大堆 RTFM'ing :-) 如果模式匹配,任何关于行号的想法也会打印在匹配行的行首 您必须使用“=”命令打印出当前行号。但是,它会在单独的行中打印行号,因此您必须运行两个 sed 实例,一个使用上面的命令递增,在每个 's///p' 行之前只包含 '=' 的行,另一个使用sed -e 'N;s/\n/ /'
加入行列。希望这会有所帮助 =)【参考方案2】:
使用 GNU awk,您可以将 RS 设置为 RE:
gawk -v RS='[[:space:]]+' '
/where/ found=0
found print
/from/ found=1
' file
以上假设您不希望打印“from”和“where”,如有必要,请移动线条。
如果有帮助,以下成语描述了如何选择给定的记录范围 要匹配的特定模式:
a) 打印某个模式的所有记录:
awk '/pattern/f=1f' file
b) 以某种模式打印所有记录:
awk 'f;/pattern/f=1' file
c) 在某种模式之后打印第 N 条记录:
awk 'c&&!--c;/pattern/c=N' file
d) 在某个模式之后打印除第 N 条记录之外的所有记录:
awk 'c&&!--cnext/pattern/c=N1' file
e) 以某种模式打印 N 条记录:
awk 'c&&c--;/pattern/c=N' file
f) 以某种模式打印除 N 条记录之外的每条记录:
awk 'c&&c--next/pattern/c=N1' file
g) 从某个模式打印 N 条记录:
awk '/pattern/c=Nc&&c--' file
我将变量名从“find”的“f”更改为“count”的“c”,其中 合适,因为这更能表达变量的实际含义。
【讨论】:
【参考方案3】:您可以为此使用ed
,它允许正则表达式范围的正负偏移。如果输入是:
seq 10 | tee > infile
1
2
3
4
5
6
7
8
9
10
将命令输入到ed
:
<<< /3/,/6/p | ed -s infile
即打印包含3
和6
的行之间的所有内容。
结果:
3
4
5
6
要在每一端多取一行:
<<< /3/-1,/5/+1p | ed -s infile
结果:
2
3
4
5
6
7
或者反过来:
<<< /3/+1,/6/-1p | ed -s infile
结果:
4
5
【讨论】:
【参考方案4】:要返回两个给定字符串中的一个字符串,按照awk
的行(不要发疯),我只运行这个非常扁平的脚本,拖曳冗长:
.\gnucoreutils\bin\awk "startstring = \"RETURN STUFF AFTER ME \"; endstring = \"RETURN STUFF BEFORE ME\"; endofstartstring = index($0,startstring)+length(startstring); print substr($0,endofstartstring,index($0,endstring)-endofstartstring)" /dev/stdin
请注意,我使用的是cmd.exe
(Windows 的命令解释器)和the gnuwin32 awk,所以请注意“双引号”和^\转义字符^\:
GNU Awk 3.1.6
Copyright (C) 1989, 1991-2007 Free Software Foundation.
请指出缺陷。
示例:
echo "hello. RETURN STUFF AFTER ME i get returned RETURN STUFF BEFORE ME my face is melting" | .\gnucoreutils\bin\awk "startstring = \"RETURN STUFF AFTER ME \"; endstring = \" RETURN STUFF BEFORE ME\"; endofstartstring = index($0,startstring)+length(startstring); print substr($0,endofstartstring,index($0,endstring)-endofstartstring)" /dev/stdin
i get returned
【讨论】:
【参考方案5】:我只用 grep 就可以做到这一点:
#> grep -A#### "start pattern" file | grep -B#### "end pattern"
问题是我必须找到正确数量的行以包含在 A 和 B 选项中,它们是相同的。 希望这会有所帮助
【讨论】:
以上是关于grep 访问多行,查找两个模式之间的所有单词的主要内容,如果未能解决你的问题,请参考以下文章
正则表达式 - 查找所有空格并忽略多行字符串中的连字符分隔的单词