替换标识结束字符的多行



我有下面的代码

CREATE TABLE Table1(
        column1 double NOT NULL,
        column2 varchar(60) NULL,
        column3 varchar(60) NULL,
        column4 double NOT NULL,
 CONSTRAINT Index1 PRIMARY KEY CLUSTERED
(
        column2 ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON PRIMARY
) ON PRIMARY
GO
GO

我想更换

 CONSTRAINT Index1 PRIMARY KEY CLUSTERED
(
        column2 ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON PRIMARY
) ON PRIMARY
GO

带有

)

您不能假设GO是文件的最后一个字符。Go之后可以有另一个表脚本。我怎么能用单sed或awk做到这一点。

更新:

您可以使用以下sed命令来替换CONSTRAINT块之前的最后一个,

sed -r '/,/{N;/CONSTRAINT/{:a;N;/GO/!ba;s/([^,]+).*/1n)/};/CONSTRAINT/!n}' input.sql

让我把它解释为一个多行脚本:

# Search for a comma
/,/ {
  # If a command was found slurp in the next line
  # and append it to the current line in pattern buffer
  N
  # If the pattern buffer does not contain the word CONSTRAINT
  # print the pattern buffer and go on with the next line of input
  # meaning start searching for a comma
  /CONSTRAINT/! n
  # If the pattern CONSTRAINT was found we loop until we find the 
  # word GO
  /CONSTRAINT/ {
    # Define a start label for the loop 
    :a
    # Append the next line of input to the pattern buffer
    N
    # If GO is still not found in the pattern buffern
    # step to the start label of the loop
    /GO/! ba
    # The loop was exited meaning the pattern GO was found.
    # We keep the first line of the pattern buffer - without
    # the comma at the end and replace everything else by a )
    s/([^,]+).*/1n)/
  }
}

您可以将上面的多行脚本保存在一个文件中,并使用执行它

sed -rf script.sed input.sql

您可以使用以下sed命令:

sed '/CONSTRAINT/{:a;N;/GO/!ba;s/.*/)/}' input.sql

该模式搜索包含/CONSTRAINT/的行。如果找到该模式,则开始在{ }之间封装一个命令块。在该块中,我们首先定义标签a:a。我们通过N获得下一行输入,并将其附加到模式缓冲区。除非我们找到模式/GO/!,否则我们将使用分支命令b继续标记a。如果找到模式CCD_ 13,我们简单地用CCD_。


一个替代方案可以使用像FredPhil建议的范围:

sed '/CONSTRAINT/,/GO/{s/GO/)/;te;d;:e}'

这可能看起来很可怕,但通过一点解释就不难理解:

SED_DELIM=$(echo -en "01")
START=' CONSTRAINT Index1 PRIMARY KEY CLUSTERED'
END='GO' 
sed -n $'x5c'"${SED_DELIM}${START}${SED_DELIM},"$'x5c'"${SED_DELIM}${END}${SED_DELIM}{s${SED_DELIM}GO${SED_DELIM})${SED_DELIM};t a;d;:a;};p" test2.txt

sed有以下形式,您可能更熟悉:
sed /regex1/,/regex2/{commands}

首先,它使用不可打印的SOH作为分隔符01
设置sed多行匹配的START和END标记
然后执行sed命令:
默认情况下-n不打印
$'x5c'是对应于反斜杠的Bash字符串文字
反斜杠是对多行范围匹配中的不可打印分隔符进行转义所必需的
{s${SED_DELIM}GO${SED_DELIM})${SED_DELIM};t a;d;:a;};p:
s${SED_DELIM}GO${SED_DELIM})${SED_DELIM})替换与GO匹配的行
t a;如果先前语句中存在成功替换,则分支到:a标签
d如果没有子教程,则删除该行
p打印命令后的任何结果的分支

在发布之前,我没有看到他们的答案-这个答案与FredPhil/hek2mgl相同-只是通过这种方式,你可以在LHS上更具动态性,因为你可以将分隔符更改为不太可能出现在数据集中的字符。

使用GNU awk for multi-char RS,并假设您想去掉"CONSTRAINT"之前的逗号:

$ cat tst.awk
BEGIN{ RS="^$"; ORS="" }
{
    gsub(/<GO>/,"34")
    gsub(/,s*CONSTRAINT[^34]+34/,")")
    gsub(/34/,"GO")
    print
}
$ gawk -f tst.awk file
CREATE TABLE Table1(
        column1 double NOT NULL,
        column2 varchar(60) NULL,
        column3 varchar(60) NULL,
        column4 double NOT NULL)
GO

上面的工作原理是将每个独立的"GO"替换为一个不太可能出现在输入中的控制字符(在这种情况下,我使用了与默认SUBSEP相同的值),这样我们就可以在中间gsub()的否定字符列表中使用该字符来创建一个regexp,该regexp以"CONSTRAINT"之后的第一个"GO"结尾。这是在awk中进行"非贪婪"匹配的一种方法。

如果没有你知道不能出现在你的输入中的字符,你可以创建一个这样的字符:

$ cat tst.awk
BEGIN{ RS="^$"; ORS="" }
{
    gsub(/a/,"aA"); gsub(/b/,"aB"); gsub(/<GO>/,"b")
    gsub(/,s*CONSTRAINT[^b]+b/,")")
    gsub(/b/,"GO"); gsub(/aB/,"b"); gsub(/aA/,"a")
    print
}
$ 
$ gawk -f tst.awk file
CREATE TABLE Table1(
        column1 double NOT NULL,
        column2 varchar(60) NULL,
        column3 varchar(60) NULL,
        column4 double NOT NULL)
GO

上面最初将所有"a"s转换为"aA",将"b"s转换成"aB",这样

  1. 记录中不再有任何"b",并且
  2. 由于现在所有原始的"a"后面都有一个"a"aB"表示"bs"最初所在的位置

这意味着我们现在可以将所有的"GO"转换为"b",就像我们在上面的第一个脚本中将它们转换为"\034"一样。然后我们执行主gsub(),然后展开我们的初始gsub(()。

gsub()创建以前不存在的字符,使用这些字符,然后展开最初的gsub()是一个非常有用的习惯用法,可以学习和记住,例如参见https://stackoverflow.com/a/13062682/1745001用于另一个应用程序。

看到它一步一步地工作:

$ cat file                                                                                                   
foo bar Hello World World able bodies
$ awk '{gsub(/a/,"aA")}1' file                                                                               
foo baAr Hello World World aAble bodies
$ awk '{gsub(/a/,"aA"); gsub(/b/,"aB")}1' file                                                               
foo aBaAr Hello World World aAaBle aBodies
$ awk '{gsub(/a/,"aA"); gsub(/b/,"aB"); gsub(/World/,"b")}1' file                                            
foo aBaAr Hello b b aAaBle aBodies
$ awk '{gsub(/a/,"aA"); gsub(/b/,"aB"); gsub(/World/,"b"); gsub(/Hello[^b]+b/,"We Are The")}1' file                         
foo aBaAr We Are The b aAaBle aBodies
$ awk '{gsub(/a/,"aA"); gsub(/b/,"aB"); gsub(/World/,"b"); gsub(/Hello[^b]+b/,"We Are The"); gsub(/b/,"World")}1' file 
foo aBaAr We Are The World aAaBle aBodies
$ awk '{gsub(/a/,"aA"); gsub(/b/,"aB"); gsub(/World/,"b"); gsub(/Hello[^b]+b/,"We Are The"); gsub(/b/,"World"); gsub(/aB/,"b")}1' file
foo baAr We Are The World aAble bodies
$ awk '{gsub(/a/,"aA"); gsub(/b/,"aB"); gsub(/World/,"b"); gsub(/Hello[^b]+b/,"We Are The"); gsub(/b/,"World"); gsub(/aB/,"b"); ; gsub(/aA/,"a")}1' file
foo bar We Are The World able bodies

最新更新