Sed模式不会产生预期的结果

时间:2015-07-22 05:18:23

标签: sed

我有一个包含大量SQL INSERT结构的文件。我正在尝试编写一个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模式不起作用。脚本正在拾取没有SELECT字的行。我正在使用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

我目前的输出是:

...inside the Into---Select range
INSERT INTO Table1 select values( val1, vale2, val3 );
 ...deleting blank line
120
...inside the Into---Select range
INSERT INTO Table2
...inside the Into---Select range
values( val1, vale2, val3 );
...inside the Into---Select range
INSERT
...inside the Into---Select range
 INTO
...inside the Into---Select range
Table3
...inside the Into---Select range
values( val1, vale2, val3 );
...inside the Into---Select range
insert into table4
...inside the Into---Select range
SELECT col1 from
...inside the Into---Select range
 INTO
...inside the Into---Select range
Table5 (col1, col2, col3)
...inside the Into---Select range
values( val1, vale2, val3 );
...inside the Into---Select range
insert into table6 (col1,
...inside the Into---Select range
col2,
...inside the Into---Select range
col3, col4
...inside the Into---Select range
)
...inside the Into---Select range
SELECT col1, col2, col3,

3 个答案:

答案 0 :(得分:2)

$ 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

如何运作

  • -r

    这告诉sed使用扩展的正则表达式语法。

  • -n

    除非我们明确要求,否则告诉sed不要打印任何内容。

  • H;1h;/;/!d;x;

    这读取将所有行读入停止的第一行带有分号的模式空间。

    更详细地说,H;1h将我们读取的每一行追加到保留空间。如果该行不包含;,则删除该行(命令d)。这具有告诉sed跳过其余命令并重新开始下一行的效果。如果我们到达x命令,则意味着最后一行包含分号;x将我们保存在保留空间中的所有内容交换回模式空间。

  • s/.*insert[[:space:]]+into[[:space:]]+([[:alnum:]]+)[[:space:]]+([(][^)]*[)][[:space:]]+)?select.*/insert into \1/Ip

    搜索该行以查找into之后和select之前的单词并打印出来。为了实现所需的输出,此命令可选地允许括号内的表达式在select之前发生。

使用范围

的替代版本
$ 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

答案 1 :(得分:1)

如果你把它放入j.sed

#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/匹配插入,并启动一个名为loop的分支。在我们到达分号之前,它会使用N将下一行附加到模式空间。

如果模式空间与SELECTselect匹配,我们将转到名为l2的分支,该分支将删除“插入tablex”之后的所有内容。我们使用p打印出该行,然后使用b转到该脚本的末尾。

如果/insert/ b loop与小写“插入”匹配,loop只会转移到<uses-sdk android:minSdkVersion="integer" android:targetSdkVersion="integer" android:maxSdkVersion="integer" />

答案 2 :(得分:1)

这可能适合你(GNU sed):

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

使用seds -nr开关调用类似grep的性质,更容易阅读regexp。忽略不包含insert的行(大写或小写)。附加以下行,直到模式空间包含终止;。寻找insert into tablename ... select的行上的模式匹配,如果匹配则用小写结果替换该行。如果模式匹配失败,则用空格替换所有空格并打印。