Regex 使用正则表达式选择性地搜索和替换某些行

Regex 使用正则表达式选择性地搜索和替换某些行,regex,sed,cygwin,grep,replace,Regex,Sed,Cygwin,Grep,Replace,我有一个包含大量SQL语句的文件,例如: CREATE TABLE "USER" ( "ID" INTEGER PRIMARY KEY, "NAME" CHARACTER VARYING(50) NOT NULL, "AGE" INTEGER NOT NULL ); COPY "USER" (id, name, age) FROM stdin; 1 Skywalker 19 2 Kenobi 57 我希望COPY语句中的列名大写并引用: COPY

我有一个包含大量SQL语句的文件,例如:

CREATE TABLE "USER" (
    "ID" INTEGER PRIMARY KEY,
    "NAME" CHARACTER VARYING(50) NOT NULL,
    "AGE" INTEGER NOT NULL
);

COPY "USER" (id, name, age) FROM stdin;
1   Skywalker   19
2   Kenobi      57
我希望
COPY
语句中的列名大写并引用:

COPY "USER" ("ID", "NAME", "AGE") FROM stdin;
使用sed,我发现了以下regexp:

sed -r 's/([( ])(\w+)([,)])/\1"\U\2\E"\3/g'
它会替换列名,但选择性不够,并替换文件中的其他单词:

~/test]$sed -r 's/([( ])(\w+)([,)])/\1"\U\2\E"\3/g' star_wars_example
CREATE TABLE "USER" (
  "ID" INTEGER PRIMARY "KEY",
  "NAME" CHARACTER VARYING("50")NOT "NULL",
  "AGE" INTEGER NOT NULL
);

COPY "USER" ("ID", "NAME", "AGE") FROM stdin;
1   Skywalker   19
2   Kenobi      57
为了避免这个问题,我希望sed只将我的regexp应用于stdin中以
COPY
开头,以
结尾的行

我已经研究了lookahead/lookahead,但是sed中不支持它们。它们似乎在超级sed中得到了支持,但我目前正在使用Cygwin(这里必须使用Windows…),而且它似乎在包列表中不可用

有没有办法强迫SED只考虑特定的线?

我考虑过在应用sed之前通过grep传输我的文件,但是其他行将从输出中消失

我错过了什么明显的东西吗


如果在默认的Cygwin安装上可以轻松地应用这个答案,那就太好了。我想我可以试着在cygwin上安装super-sed,但我想知道是否有更明显的想法

因为我目前没有可用的sed,而且从未实际使用过分组,这个命令可能会工作,也可能不会工作(完全工作,或者按预期工作)=)

试一试

如果我正确理解手册,这将在以
COPY
开头的任何行上执行替换


另一种方法是使用分支。这看起来更复杂,但更灵活。

以您的示例为例,将\w+替换为[a-z]+可能会起作用,但可能对所有内容都不够有选择性。您在这两种情况下都是正确的!我给出了一个简化的例子,但我真正担心的是会意外地替换COPY语句读取的一些数据,因为其中有很多数据……哇,非常感谢!这是完美的。虽然这解决了我遇到的问题,但我对分支方法很好奇:它是否涉及将文件变灰、查找“^COPY”,然后将结果“分支”到sed或标准输出?你会怎么做?(也许在另一个答案中贴出来,这样人们也可以投票)@eneveu:给你。我把这个编辑成了我的原始答案。但也没有经过测试。sed似乎是图灵完备的。可怕。@Jens:我从你的第二个例子中得到一个错误:“sed:-e表达式#1,char 9:未知命令:'C'”@Dennis:是的,我找到了。更正它。@Jens:现在它给出了:“sed:-e表达式#1,char 18:s的未知选项。”。提示:大多数有空格的地方应该是分号。第二条线索:你的“分支”版本没有做任何其他版本没有做的事情,除了不必要地做一个空的净效果替换。第一个示例中的选择器更简单、更直接。第三条线索:由于您的第一次替换被锚定到行的开头,因此
g
选项是无用的(而且是不需要的)。第四条线索:你可以在没有目标标签的情况下执行a
b
,它将分支到最后。
sed -r '/^COPY /{ s/([( ])(\w+)([,)])/\1"\U\2\E"\3/g }'