【问题标题】:How to delete multiple empty lines with SED?如何使用 SED 删除多个空行?
【发布时间】:2012-09-04 14:06:20
【问题描述】:

我正在尝试通过删除重复的空行来压缩文本文档,使用sed。这就是我正在做的(无济于事):

sed -i -E 's/\n{3,}/\n/g' file.txt

根据this manual,我知道这是不正确的,但我不知道如何正确地做到这一点。谢谢。

【问题讨论】:

  • 这行不通,因为sed 一次只能读取一行。将行收集到内存中,然后抑制重复的空行是可能的,但有些复杂;但这在 awk 或 Perl 中是微不足道的。是否真的需要使用sedperl -0777pi -e 's/\n{3,}/\n/g' file.txt
  • sed 不是强制性的,我可以使用perl。请发表您的建议作为答案

标签: sed text-processing


【解决方案1】:

我认为 OP 想要 compress 空行,例如如果连续 9 行 emty 行,他想只有 3 行。 我已经写了一个小 bash 脚本来做到这一点:

#! /bin/bash
TOTALLINES="$(cat file.txt|wc -l)"
CURRENTLINE=1
while [ $CURRENTLINE -le $TOTALLINES ]
do
    L1=$CURRENTLINE
    L2=$(($L1 + 1))
    L3=$(($L1 +2))
    if [[ $(cat file.txt|head -$L1|tail +$L1) == "" ]]||[[ $(cat file.txt|head -$L1|tail +$L1) == " " ]]
    then
        L1EMPTY=true
    else 
        L1EMPTY=false
    fi
    if [[ $(cat file.txt|head -$L2|tail +$L2) == "" ]]||[[ $(cat file.txt|head -$L2|tail +$L2) == " " ]]
    then
        L2EMPTY=true
    else 
        L2EMPTY=false       
    fi
    if [[ $(cat file.txt|head -$L3|tail +$L3) == "" ]]||[[ $(cat file.txt|head -$L3|tail +$L3) == " " ]]
    then
        L3EMPTY=true
    else 
        L3EMPTY=false       
    fi  
    if [    $L1EMPTY = true ]&&[    $L2EMPTY = true ]&&[    $L3EMPTY = true ]
    then
        #do not cat line to temp file
        echo "Skipping line "$CURRENTLINE   
    else
        echo "$(cat file.txt|head -$CURRENTLINE|tail +$CURRENTLINE)">>temp.txt
        echo "Writing line " $CURRENTLINE
    fi
    ((CURRENTLINE++))
done    
cat temp.txt>file.txt
rm -r temp.txt
FINALTOTALLINES="$(cat file.txt|wc -l)"
EMPTYLINELINT=$(( $CURRENTLINE - $FINALTOTALLINES ))
echo "Deleted " $EMPTYLINELINT " empty lines."

【讨论】:

    【解决方案2】:

    我不确定这是 OP 想要的,但如果您想删除文件中的所有空行,则使用 William Pursell 的 awk 解决方案是一种方法:

    awk '!/^$/' file.txt
    

    解释:

    awk 模式

    '!/^$/'
    

    正在测试当前行是否仅由行首(用'^'表示)和行尾(用'$'表示)组成,换句话说,该行是否为空。

    如果此模式为真,则 awk 应用其默认值并打印当前行。

    HTH

    【讨论】:

      【解决方案3】:

      正如上面所建议的,我使用 Perl 而不是 sed

      perl -0777pi -e 's/\n{3,}/\n\n/g'
      

      【讨论】:

        【解决方案4】:

        tr -s '\n'cat -s 处理得更好,但如果您坚持使用sed,这里有一个来自 GNU sed 手册第 4.17 节的示例:

        #!/usr/bin/sed -f
        
        # on empty lines, join with next
        # Note there is a star in the regexp
        :x
        /^\n*$/ {
          N
          bx
        }
        # now, squeeze all '\n', this can be also done by:
        # s/^\(\n\)*/\1/
        s/\n*/\
        /
        

        【讨论】:

        • 不知道cat-s 选项。谢谢!
        【解决方案5】:

        我认为您想用单个空行替换多个空行的跨度,即使您的示例用单个 \n 而不是 \n\n 替换了多次运行的 \n。考虑到这一点,这里有两种解决方案:

        sed '/^$/{ :l
            N; s/^\n$//; t l
            p; d; }' input 
        

        在 sed 的许多实现中,这可以全部在一行中,嵌入的换行符被 ; 替换。

        awk 't || !/^$/; { t = !/^$/ }'
        

        【讨论】:

        • 非常感谢 awk 解决方案。你能解释一下`t || !/^$/; ` 模式?
        • 我不得不承认,它看起来确实有点神秘!基本上,它将表达式评估为布尔值。当t 评估为真(例如,是一个非空字符串或不是0)或该行与正则表达式^$ 不匹配(即,它不是一行没有任何内容的行)时,表达式评估为真的。 ; 表示没有命令,因此 awk 应用默认值并打印该行。
        【解决方案6】:

        使用翻译功能

         tr -s '\n'
        

        -s 或 --squeeze-repeats 将重复字符序列缩减为单个实例。

        【讨论】:

        • 但这会挤压一个或多个,而不是三个或更多。
        • 这会删除 所有 个空行,而不是将多个空行压缩为一个空行。
        猜你喜欢
        • 2011-06-06
        • 2013-05-01
        • 1970-01-01
        • 2013-04-08
        • 1970-01-01
        • 1970-01-01
        • 2020-05-10
        • 2011-03-21
        相关资源
        最近更新 更多