sed:如何替换多行模式中的所有内容?

sed: How to replace all content in a multi-line pattern?

我必须从另一个更改其内容的脚本创建一个 sql 脚本。例如

SELECT value INTO val FROM table WHERE condition;
SELECT value2 INTO val2 FROM table WHERE condition1
                                   OR condition2;

所以我试过了

sed 's/FROM .*;/;/g'

但这是returns这个

SELECT value INTO val ;
SELECT value2 INTO val2 FROM table WHERE condition1
                                   OR condition2;

而不是这个,这是我需要的

SELECT value INTO val ;
SELECT value2 INTO val2 ;

有什么想法吗?基本上我想做的是删除 'FROM' 和下一个 ';' 中包含的所有内容

我认为您可以删除脚本中的“\n”,然后使用 sed 删除 from。

例如

cat test.sql |tr -d '\n'|sed 's/FROM [^;]*;/;\n/g'

据我所知,你要么必须去掉换行符

tr -d '\n'

或在re.compile

中使用Pythons"re.M | re.DOTALL"参数

例如(粗略地说):

pattern = re.compile('FROM[^;]*;', re.M | re.DOTALL)
result = re.findall(pattern, file)

通常,当我需要对换行符进行正则表达式时,我总是以 Python 结束。 Bash 太基于换行符,很难弯曲它来做到这一点。 但是,如果您确实需要使用 bash.

,则用占位符替换 '\n' 可能就足够了
sed ':load
# load any multiline sequence before going further
/;[[:space:]]*$/ !{ N;b load
   }

# from here you have a full (multi)line to treat
s/[[:space:]]\{1,\}FROM[[:space:]].*;/ ;/
   ' YourFile

您需要先加载多行序列,然后再移除结尾(序列在加载部分循环,直到找到结束的 ;

  • :load : 'goto' 后面用到的地址标签
  • /;[[:space:]]*$/:当没有结尾;就行了(最终有些结尾space以后
    • N: 在工作缓冲区中加载一个新行
    • b load : 转到标签 load (转到)
  • s/[[:space:]]\{1,\}FROM[[:space:]].*;/ ;/ 用您的新格式更改整个当前工作缓冲区(单行和多行,但都以 ; 结尾)。 Sed 在这种情况下处理缓冲区而不是一行,新行在这种情况下与其他字符一样。

最后一行需要以;结尾才能处理,否则,最后(不完整的)序列将丢失

awk是基于记录的,不像sed那样是基于行的,所以处理多行字符串没有问题:

$ awk 'BEGIN{RS=ORS=";"}{gsub(/FROM .*/,"")}1' file
SELECT value INTO val ;
SELECT value2 INTO val2 ;

上面只是将记录分隔符设置为 ; 而不是默认的换行符,并对结果字符串进行操作,它可以像任何其他字符一样包含换行符。