Grep Access多行,查找两个模式之间的所有单词

时间:2012-10-16 15:34:25

标签: awk sed line

需要帮助扫描文本文件并找到两种模式之间的所有单词。就像说如果我们有一个.sql文件,需要扫描并找到'和'之间的所有单词'。 Grep一次只能扫描1行。对于此要求,最好使用的unix脚本是什么? sed,awk有这些功能吗?非常感谢指出任何例子。

5 个答案:

答案 0 :(得分:22)

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脚本编写)稍微复杂一些,我将尝试解释详细信息。

第一行是在包含fromwhere的行上执行的。如果一行与该模式匹配,则执行两个命令。我们使用s替换命令仅提取from和where之间的部分(包括from和where)。该命令中的p后缀打印该行。 delete命令清除模式空间(工作缓冲区),加载下一行并重新启动脚本。

当找到包含from的行时,第二个命令开始执行一系列命令(按大括号分组)。基本上,这些命令形成一个循环,该循环将保持从输入到模式空间的附加行,直到找到具有where的行或直到我们到达最后一行。

:“命令”在脚本中创建一个标签,一个标记,允许我们在需要时“跳回”。 N命令从输入中读取一行,并将其附加到模式空间(用换行符分隔行)。

当找到where时,我们可以打印出模式空间的内容,但首先我们必须用substitute命令清除它。它类似于之前使用的那个,但我们现在用.*替换前导和尾随[^\n]*,它告诉sed只匹配非换行符,有效地匹配第一行中的from和在最后一行的位置。然后d命令清除模式空间并在下一行重新启动脚本。

b命令将跳转到标签,在我们的示例中为标签next。但是,$!地址表示不应该在最后一行执行,允许我们离开循环。当我以这种方式离开循环时,我们没有找到相应的where,因此您可能不想打印它。

但请注意,这有一些缺点。以下情况不会按预期处理:

from ... where ... from

from ... from
where

from
where ... where

from
from
where
where

处理这些案件需要更多代码。

希望这有助于=)

答案 1 :(得分:2)

使用GNU awk,您可以将RS设置为RE:

gawk -v RS='[[:space:]]+' '
   /where/ { found=0 }
   found   {  print  }
   /from/  { found=1 }
' file

以上假设您不希望打印“from”和“where”,如有必要,可以移动线条。

如果有帮助,以下习语描述了如何选择给定的记录范围 要匹配的特定模式:

a)打印某些模式的所有记录:

awk '/pattern/{f=1}f' file

b)在某种模式之后打印所有记录:

awk 'f;/pattern/{f=1}' file

c)在某种模式后打印第N条记录:

awk 'c&&!--c;/pattern/{c=N}' file

d)在某种模式之后打印除第N条记录以外的所有记录:

awk 'c&&!--c{next}/pattern/{c=N}1' file

e)在某种模式之后打印N条记录:

awk 'c&&c--;/pattern/{c=N}' file

f)在某种模式之后打印除N条记录之外的所有记录:

awk 'c&&c--{next}/pattern/{c=N}1' file

g)从某种模式打印N条记录:

awk '/pattern/{c=N}c&&c--' file

我将变量名称从“f”更改为“found”到“c”更改为“count” 适当的,因为它更能表达变量实际上是什么。

答案 2 :(得分:1)

您可以使用ed,它允许正则表达式范围的正负偏移。如果输入是:

seq 10 | tee > infile
1
2
3
4
5
6
7
8
9
10

将命令传递给ed

<<< /3/,/6/p | ed -s infile

即。在包含36的行之间打印所有内容。

结果:

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

答案 3 :(得分:1)

我只用grep:

完成了这个
#> grep -A#### "start pattern" file | grep -B#### "end pattern"

问题在于我必须找到包含在A和B选项中的正确数量的行,这些行是相同的。 希望这有帮助

答案 4 :(得分:0)

要返回两个给定字符串中的一个字符串,沿着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