在扫描文本文件和查找两种模式之间的所有单词时需要帮助。比如说如果我们有一个 .sql 文件,需要扫描并找到 from' 和 'where' 之间的所有单词。Grep 一次只能扫描 1 行。对于这个要求,最好使用的 unix 脚本是什么?sed、awk有这些功能吗?非常感谢您指出任何示例。
5 回答
Sed 有这个:
sed -n -e '/from/,/where/ p' file.sql
打印带有 afrom
的行和带有 a 的行之间的所有行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 脚本)稍微复杂一些,我将尝试解释细节。
第一行在包含 afrom
和 a的行上执行where
。如果一行与该模式匹配,则执行两个命令。我们使用s
替换命令仅提取 from 和 where 之间的部分(包括 from 和 where)。该p
命令中的后缀打印该行。delete 命令清除模式空间(工作缓冲区),加载下一行并重新启动脚本。
当找到包含的行时,第二个命令开始执行一系列命令(由大括号分组)from
。基本上,这些命令形成一个循环,它将不断将输入中的行追加到模式空间中,直到找到带有 a 的行where
或直到我们到达最后一行。
“:
命令”创建一个标签,脚本中的一个标记,允许我们在需要时“跳”回来。该N
命令从输入中读取一行,并将其附加到模式空间(用换行符分隔行)。
当where
找到 a 时,我们可以打印出模式空间的内容,但首先我们必须用替换命令清理它。它与之前使用的类似,但我们现在用 替换前导和尾随.*
,[^\n]*
这告诉 sed 仅匹配非换行符,有效地匹配第一行中的 a from 和最后一行中的 a where。然后该d
命令清除模式空间并在下一行重新启动脚本。
该b
命令将跳转到一个标签,在我们的例子中是 label next
。但是,$!
地址说它不应该在最后一行执行,让我们离开循环。以这种方式离开循环时,我们没有找到相应的where
,因此您可能不想打印它。
但是请注意,这有一些缺点。以下情况将不会按预期处理:
from ... where ... from
from ... from
where
from
where ... where
from
from
where
where
处理这些情况需要更多代码。
希望这会有所帮助=)
使用 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
我将变量名称从“found”的“f”更改为“count”的“c”,因为这更能表达变量的实际含义。
您可以使用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
我只用 grep 就可以做到这一点:
#> grep -A#### "start pattern" file | grep -B#### "end pattern"
问题是我必须找到正确数量的行来包含在 A 和 B 选项中,它们是相同的。希望这可以帮助
为了只返回两个给定字符串中的一个字符串,按照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 的命令解释器)和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