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

Bash 使sed忽略多行单引号或双引号块,bash,sed,Bash,Sed,假设我有一个包含以下内容的shell脚本: echo "This is a single-line text" echo " Examples: 1 2 3 4 " 现在我想要的是从每一行的开头去掉多余的空间: 我不是任何使用sed的专家,所以到目前为止我尝试的是sed-I的| ^ | | |文件,但这也与多行引号块中的匹配,我不希望它这样做

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

    echo "This is a single-line text"

    echo "
Examples:   1
            2
            3
            4
    "
    
现在我想要的是从每一行的开头去掉多余的空间:

我不是任何使用
sed
的专家,所以到目前为止我尝试的是
sed-I的| ^ | | |文件
,但这也与多行引号块中的匹配,我不希望它这样做

sed-i的| ^ | |文件
以以下内容结尾:

echo“这是单行文本”
回声“
示例:1
2.
3.
4.
"
但我想会是这样的:

echo“这是单行文本”
回声“
示例:1
2.
3.
4.
"
所以,我怎样才能使sed忽略这种模式呢?我也同意任何基于
awk
的解决方案

谢谢。

假设:

  • 倒数第二行由
    4个空格组成
    +
    ;这些空格不应被删除,因为它们位于引用的文本块内
  • 最后一行仅包含
    4个空格
    ,并将被修剪为空行
  • 不必担心任何边缘情况(参见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''…
  • 注释中显示的双引号(
    #这是双引号(“)
如果
打印
行更改为
打印“$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
    "

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

.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
    "

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

假设:

  • 倒数第二行由
    4个空格组成
    +
    ;这些空格不应被删除,因为它们位于引用的文本块内
  • 最后一行仅包含
    4个空格
    ,并将被修剪为空行
  • 不必担心任何边缘情况(参见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''…
  • 注释中显示的双引号(
    #这是双引号(“)
如果
打印
行更改为
打印“$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
    "

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

.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表示gensub()和RT:

或使用任何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 }
警告:任何解决方案都是脆弱的,除非您为shell语言编写一个解析器,能够理解
何时在字符串、脚本、转义等中。

使用GNU awk for gensub()和RT:

或使用任何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 }

警告:任何解决方案都是脆弱的,除非您为shell语言编写一个解析器,能够理解
何时在字符串、脚本、转义等中。

sed的/^*echo/echo/”文件
?我不是专门针对
echo
。我指的是任何多行带引号的字符串。我只想让sed忽略这种模式。从逻辑上讲,最后一行中的前导空格也在双引号块中,它们不应该被删除。如果要删除它们,我们需要指定另一个条件。TBH,除非不是1000行,否则我建议在一个好的文本编辑器中手动执行。有太多的极端情况,以至于您编写的任何解决方案都需要“\”$(一个完整的“shell”解析器“)”。在sed中实现这一点几乎是不可能的,因为sed主要是一个行编辑器,多行在sed中很难实现。
sed的/^*echo/echo/”文件
?我不是专门针对
echo
。我指的是任何多行带引号的字符串。我只想让sed忽略这种模式。从逻辑上讲,最后一行中的前导空格也在双引号块中,它们不应该被删除。如果要删除它们,我们需要指定另一个条件。TBH,除非不是1000行,否则我建议在一个好的文本编辑器中手动执行。有太多的极端情况,以至于您编写的任何解决方案都需要“\”$(一个完整的“shell”解析器“)”。在sed中这样做几乎是不可能的,因为sed主要是一个行编辑器,多行在sed中很难。这似乎对我身边的东西很有效,是的,你的笔记是有效的,但对我来说不是问题。这似乎对我身边的东西很有效,是的,你的笔记是有效的,但对我来说不是问题。