Sed模式不会产生预期结果
我有一个包含大量SQL插入结构的文件。我试图编写一个sed脚本来提取包含INSERT表名的行Sed模式不会产生预期结果,sed,Sed,我有一个包含大量SQL插入结构的文件。我试图编写一个sed脚本来提取包含INSERT表名的行 INSERT INTO Table1 values( val1, vale2, val3 ); INSERT INTO Table2 VALUES( val1, vale2, val3 ); INSERT INTO Table3 VALUES( val1, vale2, val3 ); insert into table4 SE
INSERT INTO Table1 values( val1, vale2, val3 );
INSERT INTO Table2
VALUES( val1, vale2, val3 );
INSERT
INTO
Table3
VALUES( val1, vale2, val3 );
insert into table4
SELECT col1 from
table4
where condition1 = condition2
;
INSERT
INTO
table5 (col1, col2, col3)
VALUES( val1, vale2, val3 );
insert into table6 (col1,
col2,
col3, col4
)
SELECT col1, col2, col3,
col4 FROM
table6
WHEREcondition1 = condition2
;
我的输出应该是:
insert into table4
insert into table6
这就是我尝试过的。然而,我不确定我的sed模式为什么不起作用。脚本正在拾取没有选择词的行。我使用的是GNU sed 4.2。我们将非常感谢您的帮助
# select all lines between INSERT and ;
sed -n '/Insert/I,/;/ {
#delete the blank line
/^\s*$/{
i\ ...deleting blank line
=
d}
#selecting sub pattern range between INTO and SELECT
/into/I, /Select/I {
i\
...inside the Into---Select range
p
}
}' < testfile
如果你把这个放进j
#n
/INSERT/{
:loop
/;/!{
N
b loop
}
/SELECT/{
:l2
s/\([^a]*able.\).*/\1/
p
b
}
/select/b l2
}
/insert/b loop
跑
sed -f j.sed foo.txt
这将输出
insert into table4
insert into table6
解释
#n
抑制正常输出
/INSERT/
匹配INSERT,并启动名为循环的分支。在到达分号之前,它使用N
将下一行追加到模式空间
如果模式空间与SELECT
或SELECT
匹配,我们将转到名为l2
的分支,该分支将删除“insert into tablex”之后的所有内容。我们使用p
打印该行,并使用b
转到脚本末尾
/insert/b循环
如果与小写“insert”匹配,则只会分支到循环
工作原理
-r
这告诉sed使用扩展正则表达式语法
-n
这告诉sed,除非我们明确要求,否则不要打印任何内容
H;1h;/;/!Dx代码>
这会将所有行读入模式空间,并以第一行分号结尾
更详细地说,H;1h
将我们读取的每一行追加到保留空间。如果该行不包含
,然后我们删除该行(命令d
)。这会告诉sed跳过其余的命令,并从下一行开始。如果我们使用x
命令,这意味着最后一行包含一个分号,代码>x
将保存在保留空间中的所有内容交换回模式空间
s/*将[[:space:][]+插入[[:space:][]+([[:alnum:][]+)[[:space:][]+([([])[^]]*[][:space:][]+)?选择。*/插入\1/Ip
这将搜索该行,以在之后和之前找到单词,然后选择并打印它。为了获得所需的输出,此命令允许在select
之前出现括号内的表达式
使用范围的替代版本
这可能适用于您(GNU-sed):
使用seds-nr
开关调用类似grep的性质,并且更易于阅读regexp。忽略不包含插入内容的行(小写或大写)。追加以下行,直到模式空间包含终止代码>。查找插入到tablename中的行上的模式匹配。。。选择
,如果匹配,则用小写结果替换该行。如果模式匹配失败,请退出,否则将所有空格替换为空格并打印。在您的示例中,为什么在没有select语句的情况下输出表5?您是否尝试过使用awk
而不是sed
?在多行输入时,它往往工作得更好。如果您是对的。不应该。我已经更正了输出。@Etan,因为SED已经被使用了,所以只使用SED进行了尝试。@Samar我看你是新手。由于你的问题有很多答案,如果你觉得合适的话,请考虑接受一个。我可以遵循第一部分,你把所有的行都附加到当前的模式空间中,直到Word;然后搜索并根据“表格”选择并打印第一部分。你能详细解释一下这个逻辑吗?由于表名不以“table”开头,因此可能需要根据“INTO”进行更改<代码>:循环/;/!{nb loop}
它的作用是启动一个名为loop
的分支,/;/
表示不匹配分号,然后我们附加N
,并返回到循环的开头,在到达分号后,我们检查模式空间是否匹配select,/select/{:l2 s/\([^a]*able.\)./\1/p b}
如果匹配“select”,我们创建了一个名为l2
的新分支,s/\([^a]*able.\)./\1/
所做的是从行的开头捕获到tablex,并用捕获的组替换整行。我们打印出编辑好的行,然后用b
Thank bk进入脚本末尾。您的帖子向我展示了如何在文件中使用sed命令。虽然有一个问题让我困惑,为什么嵌套模式匹配在这种情况下会失败。你能给我一个嵌套模式失败的例子吗?谢谢波通。这是最符合我需要的。但是,我需要一些澄清:是否\S用于字符串类?什么是\l和T?如果您查看我的示例文件,您会发现很少有INSERT构造是由“values”字组成的。所以我添加了(选择|值)。然而,我注意到,对于带有“values”的INSERT,它们唯一的第一个单词改为小写。虽然这不是问题,但我想知道为什么?这是输出:iNSERT INTO Table1 iNSERT INTO TABLE2我知道\l和\S,除了'T'。正如你所说,这是为了纾困。这是一种没有标签的分支吗?我刚刚尝试了没有“T”的sed命令。它工作正常,输出没有差异。我只是试着用这行来看看它打印了什么。sed-nr'/insert/I{H;1h;/;/!d;x;p}'insert into table4
insert into table6
$ sed -rn 'H;1h;/;/!d;x; s/.*insert[[:space:]]+into[[:space:]]+([[:alnum:]]+)[[:space:]]+([(][^)]*[)][[:space:]]+)?select.*/insert into \1/Ip' file
insert into table4
insert into table6
$ sed -rn '/insert/I,/;/{H;/;/!d;x; s/.*insert[[:space:]]+into[[:space:]]+([[:alnum:]]+)[[:space:]]+([(][^)]*[)][[:space:]]+)?select.*/insert into \1/Ip}' file
insert into table4
insert into table6
sed -nr '/insert/I{:a;/;/!{$!{N;ba}};s/^\s*(insert\s+into\s+\S+)\s+(\([^)]*\))*\s*select.*/\l\1/i;T;s/\s+/ /gp}' file