我有一个包含以下代码的文件test.txt
。
select * from emp where empid=1;
select *
from dep
where jkdsfj
select *
from sal
where jkdsfj
我需要在“from”和“where”之间提取内容。
注意:如果新行上有“where”,它仍然必须选择“from”和“where”之间的材料。
输出应该是:
emp
dep
sal
我该怎么做?
答案 0 :(得分:2)
鉴于需要处理多行,您可以选择sed
或awk
,或者选择一种更复杂的脚本语言,如Perl或Python。
谨慎一点,sed
就足够了。我创建了一个文件script.4
(创建了script
,script2
,丢失了大部分头发留在我头上的 ** ,然后重新启动{ {1}},script.1
和script.2
,这些都是故意不完整的),如下所示:
script.3
我创建了一个测试文件/from.*where/ { s/.*from *//; s/ *where.*//; p; n; }
/from/,/where/ { s/.*from *//; s/ *where.*//; /^ *$/d; p; }
,如下所示:
data
并像这样运行命令,以显示输出:
select * from emp where empid=1;
select *
from dep
where jkdsfj
select *
from sal
where jkdsfj
select elephants
from abject poverty
join flying tigers
where abelone = shellfish;
select mouse
from toolset
join animals where tail = cord
and buttons = legs
脚本简单'。对于同时包含$ sed -n -f script.4 data
emp
dep
sal
abject poverty
join flying tigers
toolset
join animals
$
和from
的行,请删除where
之后的所有内容(以及后面的任何空格),删除from
之前的所有内容(以及之前的任何空格) it),打印剩下的内容,然后转到下一行输入。
否则,在包含where
的行和包含from
的行之间,
删除where
之后的所有内容(以及后面的任何空格),删除from
以后的所有内容(加上前面的任何空格),如果该行为空,则将其删除;否则打印出来。请注意,向第二行添加where
命令会导致脚本行为异常(我需要花时间计算原因),但删除操作可以添加到第一个命令行而不会造成任何伤害(如果一行包含n
,没有打印任何内容。
请注意,有许多SELECT语句会被此代码错误处理。
例如:
from where
除了大写关键字之外,子查询中的WHERE将是FROM和WHERE之间的匹配停止的位置。
**如果您对脱发的原因感到好奇,请查看Why does an n
instead of a b
or d
or nothing change the behaviour of sed
in this script?。
答案 1 :(得分:0)
Jonathan Leffler's answer中提到的警告适用:不能使用嵌套 SQL语句。
这是一个结合tr
和sed
的实用解决方案:
使用 GNU Sed:
tr -s ' ' '\n' < test.txt | sed -n '/^from$/I,/^where$/I { s///; t; p; }'
使用 BSD Sed(也用于OSX;这是一个符合POSIX标准的解决方案,也与GNU Sed一起使用) - 请注意使用I
不幸的是,在 BSD Sed中不支持不区分大小写的匹配,因此以下内容仅匹配全小写from
和where
:
tr -s ' ' '\n' < test.txt | sed -n -e '/^from$/,/^where$/ { s///; t' -e 'p; }'
tr -s ' ' '\n'
有效地将输入拆分为单独的令牌,每个令牌都在一个单独的行上。sed
命令然后提取表名:
t
之后的换行符,在这种情况下,通过将其余脚本作为单独的{{1}提供隐式提供。选项:-e
匹配行的范围,包括 /^from$/,/^where$/
和from
行。where
是一种跳过s///; t
和from
行的技巧,实际上只打印(where
)之间的 他们:
p
是一个虚拟替换:
s///
内的正则表达式意味着重复使用与当前行//
然后分支 - 在没有目标标签名称的情况下 - 到脚本的 end ,如果发生了替换 - 这只是端点范围,有效地跳过它们。t
- 即打印当前行 - 仅针对 p
和from
行之间的行执行。 警告:如果在where
和from
之间存在多个以空格分隔的标记,则它们将在单独的行中输出。< / p>
答案 2 :(得分:0)
Jonathan Leffler's answer中提到的警告适用:不适用于嵌套 SQL语句。
如果您使用的是 GNU grep
(如Linux上所示),请尝试以下操作:
tr -s '\n' ' ' < test.txt | grep -Pio '(?<= from ).*?(?= where )'
tr -s '\n' ' '
替换每行带有空格的换行符,从而生成单个行。
from
/ where
对内的令牌跨越多行,则会将它们输出为单行,以空格分隔的列表。)grep
命令:
-P
激活对PCRE(Perl兼容的正则表达式)的支持,它提供了先行和后置断言等高级功能。-o
导致Grep仅输出每行的匹配部分,而i
执行不区分大小写的匹配。(?<= from )
使用后备断言来匹配from
而不将其包含在匹配中(?<= where )
使用预见断言匹配where
,而不将其包含在匹配中.*?
非贪婪地匹配任何字符序列;非贪婪修饰符?
是阻止.*
通过输入行上 last 出现的where
进行匹配所必需的。 BSD grep
(也在OSX上使用)不支持-P
,因此需要额外的提取步骤来删除from
和来自匹配项的where
关键字,使用awk
:
tr -s '\n' ' ' < test.txt | grep -Eio ' from .*? where ' |
awk -F ' from | where ' '{ print $2 }'
答案 3 :(得分:-1)
不漂亮,但工作(在同一条线上):
grep "from.*where" test.txt | awk '{ print $2 }'
对于通用解决方案,我使用python,因为grep不能用于多行。