使sed忽略多行单引号或双引号块

  • 本文关键字:单引号 sed bash sed
  • 更新时间 :
  • 英文 :


假设我有一个包含以下内容的shell脚本:

echo "This is a single-line text"
echo "
Examples:   1
2
3
4
"

现在我想要的是从每行的开头去掉多余的空间:

我不是使用sed的专家,所以到目前为止我尝试过的是sed -i 's|^ ||' file,但这也与多行引用块匹配,我不希望它这样做

sed -i 's|^ ||' file最终为:

echo "This is a single-line text"
echo "
Examples:   1
2
3
4
"

但我预计它会是这样的:

echo "This is a single-line text"
echo "
Examples:   1
2
3
4
"

那么,我怎么能让sed忽略这样的模式呢?我也可以接受任何基于awk的解决方案。

谢谢。

假设:

  • 倒数第二行由4 spaces+"组成;这些空格不应被删除,因为它们位于带引号的文本块内
  • 最后一行仅由4 spaces组成,并将被修剪为空行
  • 不必担心任何边缘案例(参见KamilCuk的评论(

一个基于跟踪我们遇到的双引号("(数量的awk想法:

awk '
/^    / { if ( qtcnt % 2 == 0 )         # if current line starts with 4 spaces and we
# have seen an even number of double quotes
# prior to this line (ie, we are outside
# of a double quoted string) then ...
$0=substr($0,5)            # remove the 4 spaces from the current line
}
{ print $0 }                    # print the current line
{ n=split($0,arr,""")          # split the current line on double quotes and
# get a count of the number of fields
if ( n >=1 )                  # if number of fields >= 1 (ie, line contains
# at least one double quote) then ...
qtcnt += n - 1             # increment our quote counter
}
' indent.dat

注意

  • 在以下情况下,这将错误地计算双引号
  • 转义双引号("(
  • 单引号双引号(awk -F'"' ...(
  • 出现在注释中的双引号(# this is a double quote (")(

如果print行更改为print "."$0"."(使用句点作为视觉分隔符(,则会生成以下内容:

.echo "This is a single-line text".
..
.echo ".
.Examples:   1.
.            2.
.            3.
.            4.
.    ".
..

按编码(无周期(生成以下内容:

echo "This is a single-line text"
echo "
Examples:   1
2
3
4
"

注意:最后一行为空/空白

使用GNU awk for gensub((和RT:

$ cat tst.awk
BEGIN { RS="""; ORS="" }
NR%2 { $0 = gensub(/(^|n)[[:blank:]]+/,"\1","g") }
{ print gensub(/n[[:blank:]]+$/,"n",1) RT }

$ awk -f tst.awk file
echo "This is a single-line text"
echo "
Examples:   1
2
3
4
"

或使用任何POSIX awk:

$ cat tst.awk
BEGIN { RS=ORS=""" }
NR > 1 { print prev }
NR%2 {
sub(/^[[:blank:]]+/,"")
gsub(/n[[:blank:]]+/,"n")
}
!(NR%2) {
sub(/n[[:blank:]]+$/,"n")
}
{ prev = $0 }
END { printf "%s", prev }

$ awk -f tst.awk file
echo "This is a single-line text"
echo "
Examples:   1
2
3
4
"

注意:任何解决方案都是脆弱的,除非你为shell语言编写一个解析器,它可以理解"何时在字符串、脚本、转义等中。

最新更新