Shell 替换标识结束字符的多行
我有下面的代码Shell 替换标识结束字符的多行,shell,awk,sed,Shell,Awk,Sed,我有下面的代码 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,
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命令替换约束块之前的最后一个约束块:
让我将其解释为多行脚本:
# 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命令:
模式将搜索包含/CONSTRAINT/的行。如果找到该模式,将在{}之间开始包装一个命令块。在块中,我们首先定义一个标签a到:a。我们通过N获得下一行输入,并将其附加到模式缓冲区。除非我们找到模式/开始!我们将使用branch命令b继续标记a。如果找到模式/GO/,我们只需将缓冲区替换为一个
另一种方法是使用Fredfil建议的范围:
sed '/CONSTRAINT/,/GO/{s/GO/)/;te;d;:e}'
更新:
可以使用以下sed命令替换约束块之前的最后一个约束块:
让我将其解释为多行脚本:
# 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命令:
模式将搜索包含/CONSTRAINT/的行。如果找到该模式,将在{}之间开始包装一个命令块。在块中,我们首先定义一个标签a到:a。我们通过N获得下一行输入,并将其附加到模式缓冲区。除非我们找到模式/开始!我们将使用branch命令b继续标记a。如果找到模式/GO/,我们只需将缓冲区替换为一个
另一种方法是使用Fredfil建议的范围:
sed '/CONSTRAINT/,/GO/{s/GO/)/;te;d;:e}'
使用GNU awk表示多字符,并假设您希望在约束之前去掉逗号:
$ 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
使用GNU awk表示多字符,并假设您希望在约束之前去掉逗号:
$ 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
这可能看起来很吓人,但稍加解释就不难理解:
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 non printable作为分隔符\001
设置sed多行匹配的开始和结束标记
然后执行sed命令:
-n默认情况下不打印
$'\x5c'是对应于反斜杠的Bash字符串文字\
反斜杠是在多行范围匹配上转义不可打印分隔符所必需的。
{s${SED_DELIM}GO${SED_DELIM}${SED_DELIM};ta;d;:a;};p:
s${SED_DELIM}GO${SED_DELIM}${SED_DELIM}替换与GO匹配的行
tα;如果前面的语句中有成功的替换,则分支到:a标签
d如果没有替代品,则删除该行
p打印命令后的结果
分支机构
在发布这篇文章之前,我没有看到他们的答案-这个答案与FredPhil/hek2mgl相同-除了通过这种方式,您可以在LHS上使用更动态的机制,因为您可以将分隔符更改为不太可能出现在数据集中的字符 这可能看起来很吓人,但稍加解释就不难理解:
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 non printable作为分隔符\001
设置sed多行匹配的开始和结束标记
然后执行sed命令:
-n默认情况下不打印
$'\x5c'是对应于反斜杠的Bash字符串文字\
反斜杠是在多行范围匹配上转义不可打印分隔符所必需的。
{s${SED_DELIM}GO${SED_DELIM}${SED_DELIM};ta;d;:a;};p:
s${SED_DELIM}GO${SED_DELIM}${SED_DELIM}替换与GO匹配的行
tα;如果前面的语句中有成功的替换,则分支到:a标签
d如果没有替代品,则删除该行
p打印命令后的结果
分支机构
在发布这篇文章之前,我没有看到他们的答案-这个答案与FredPhil/hek2mgl相同-除了通过这种方式,您可以在LHS上使用更动态的机制,因为您可以将分隔符更改为不太可能出现在数据集中的字符 像往常一样,请发布你尝试过的…像往常一样,请发布你尝试过的…没有必要重复GO regex//s/*//足够了。///再次尝试最后一个正则表达式感谢您的回复。我想从最后一个逗号开始替换。表示我也要替换最后一个逗号。另外,请您提供我的链接,我可以阅读有关搜索和使用标签和替换buffer@Koushik我真的很喜欢这个教程:。让我把答案改成逗号。@hek2mgl我对了一半,你找到了另一半。当然,再次测试正则表达式是非常困难的
没必要!很好。没有必要重复GO regex//s/*//足够了。///再次尝试最后一个正则表达式感谢您的回复。我想从最后一个逗号开始替换。表示我也要替换最后一个逗号。另外,请您提供我的链接,我可以阅读有关搜索和使用标签和替换buffer@Koushik我真的很喜欢这个教程:。让我把答案改成逗号。@hek2mgl我对了一半,你找到了另一半。当然,再次测试正则表达式是完全没有必要的!很好。我不确定OP是否真的想用硬编码内容替换约束。可能他想替换所有表定义中的每个约束定义。我可以想象这样一种情况:您希望将数据库转储从支持约束的数据库处理到不支持约束的数据库。然而,这并不能解释GO的声明。可能您可以推广awk命令,希望看到您的尝试+1对于awk备选方案,无论如何。。。虽然我认为sed代码在这种情况下相对容易编写和维护,但并不完全如此。您还需要从具有约束的行之前的行中删除,然后将以下所有行(包括第一行)替换为一行。我用了一个循环。是的,看看我答案下面的评论。否则会在SQL中出现语法错误。。。请注意,我需要是AFK,稍后将在此处查看OK,我更新了我的答案,只删除了,约束和第一次执行之间的任何内容。我不确定OP是否真的想用硬编码内容替换约束。可能他想替换所有表定义中的每个约束定义。我可以想象这样一种情况:您希望将数据库转储从支持约束的数据库处理到不支持约束的数据库。然而,这并不能解释GO的声明。可能您可以推广awk命令,希望看到您的尝试+1对于awk备选方案,无论如何。。。虽然我认为sed代码在这种情况下相对容易编写和维护,但并不完全如此。您还需要从具有约束的行之前的行中删除,然后将以下所有行(包括第一行)替换为一行。我用了一个循环。是的,看看我答案下面的评论。否则会在SQL中出现语法错误。。。请注意,我需要是AFK,稍后将在这里查看OK,我更新了我的答案,只删除了,约束和第一次执行之间的任何内容。