我有以下代码
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做到这一点。
答案 0 :(得分:2)
<强>更新强>
您可以使用以下sed
命令替换,
块之前的最后CONSTRAINT
:
sed -r '/,/{N;/CONSTRAINT/{:a;N;/GO/!ba;s/([^,]+).*/\1\n)/};/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/([^,]+).*/\1\n)/
}
}
您可以将上述多行脚本保存在文件中并使用
执行sed -rf script.sed input.sql
您可以使用以下sed
命令:
sed '/CONSTRAINT/{:a;N;/GO/!ba;s/.*/)/}' input.sql
模式搜索包含/CONSTRAINT/
的行。如果找到模式,则会在{ }
之间启动一个命令块。在块中,我们首先定义标签a
到:a
。我们通过N
得到下一行输入,并将其附加到模式缓冲区。除非我们找到模式/GO/!
,否则我们将使用分支命令a
继续标记b
。如果找到模式/GO/
,我们只需用)
替换缓冲区。
替代方案可以使用像FredPhil建议的范围:
sed '/CONSTRAINT/,/GO/{s/GO/)/;te;d;:e}'
答案 1 :(得分:1)
使用GNU awk进行多字符RS并假设您想要在&#34; CONSTRAINT&#34;之前删除逗号:
$ cat tst.awk
BEGIN{ RS="^$"; ORS="" }
{
gsub(/\<GO\>/,"\034")
gsub(/,\s*CONSTRAINT[^\034]+\034/,")")
gsub(/\034/,"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
上述工作取代了每一个单独的&#34; GO&#34;使用控件char不太可能出现在您的输入中(在这种情况下,我使用与默认SUBSEP相同的值),因此我们可以在中间gsub()中的否定字符列表中使用该char来创建regexp结束于第一个&#34; GO&#34;在&#34; CONSTRAINT&#34;之后。这是一种做法&#34;非贪婪&#34;在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
以上最初将所有&#34; a&#34; s转换为&#34; aA&#34;和&#34; b&#34; s到&#34; aB&#34;这样
这意味着我们现在可以将所有&#34; GO&#34; s转换为&#34; b&#34; s就像我们将它们转换为&#34; \ 034&#34;在上面的第一个脚本中。然后我们做主gsub(),然后展开我们的初始gsub()s。
{{1}创建使用这些字符以前无法存在的字符,然后展开初始gsub()
的这个想法是一个非常有用的学习和记忆习惯,例如,请参阅https://stackoverflow.com/a/13062682/1745001了解其他申请。
要看到它一次只能工作一步:
gsub()
答案 2 :(得分:1)
这可能看起来很可怕,但通过一些解释并不难理解:
SED_DELIM=$(echo -en "\001")
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不可打印作为分隔符\001
设置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上更加动态,因为你可以将分隔符更改为不太可能出现在数据集中的字符。