Sed模式不会产生预期结果

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

我有一个包含大量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
    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