sed '/^$/d' 和 grep -Ev '^$' 无法删除空行

sed '/^$/d' 和 grep -Ev '^$' 无法删除空行

我在 vscode 中有一个这样的文件,里面有多个空行

$ tail -n 20 draft3.py
            hi = len(a)  

        if lo < 0:
            raise ValueError('low must be non-negative')

        if lo == hi: 
            return None 

        mid = (lo + hi) // 2

        if x == a[mid]:
            return x
        if x > a[mid]:

            lo = mid + 1
            return self.bi_search(a, x, lo, hi)
        if x < a[mid]:

            hi = mid
            return self.bi_search(a, x, lo, hi)

尝试了多种方法删除空白行

`grep -v -e '^$' 失败

$ tail -n 20 draft3.py | grep -v -e '^$'
            hi = len(a)  
        if lo < 0:
            raise ValueError('low must be non-negative')
        if lo == hi: 
            return None 
        mid = (lo + hi) // 2

        if x == a[mid]:
            return x
        if x > a[mid]:

            lo = mid + 1
            return self.bi_search(a, x, lo, hi)
        if x < a[mid]:

            hi = mid
            return self.bi_search(a, x, lo, hi)

`grep -Ev“^$”失败

$ tail -n 20 draft3.py | grep -Ev "^$" 
            hi = len(a)  
        if lo < 0:
            raise ValueError('low must be non-negative')
        if lo == hi: 
            return None 
        mid = (lo + hi) // 2

        if x == a[mid]:
            return x
        if x > a[mid]:

            lo = mid + 1
            return self.bi_search(a, x, lo, hi)
        if x < a[mid]:

            hi = mid
            return self.bi_search(a, x, lo, hi)

`sed '/^$/d' 失败

$ tail -n 20 draft3.py | sed '/^$/d'
            hi = len(a)  
        if lo < 0:
            raise ValueError('low must be non-negative')
        if lo == hi: 
            return None 
        mid = (lo + hi) // 2

        if x == a[mid]:
            return x
        if x > a[mid]:

            lo = mid + 1
            return self.bi_search(a, x, lo, hi)
        if x < a[mid]:

            hi = mid
            return self.bi_search(a, x, lo, hi)

有什么问题?如何删除空白行?

答案1

假设您不仅想删除空行,还想删除仅包含空格字符的行。为此,请使用:

sed '/^\s*$/d'   # or respectively
grep -v '^\s*$'

sed表达式选出其中d含有任意数量 ( *) 个空格字符 ( ) 的每一行。输出与表达式不匹配的任何行。\sgrep -v

示例用法

$ sed '/^\s*$/d' <draft3.py 
            hi = len(a)  
        if lo < 0:
            raise ValueError('low must be non-negative')
        if lo == hi: 
            return None 
        mid = (lo + hi) // 2
        if x == a[mid]:
            return x
        if x > a[mid]:
            lo = mid + 1
            return self.bi_search(a, x, lo, hi)
        if x < a[mid]:
            hi = mid
            return self.bi_search(a, x, lo, hi)

答案2

grep -v '^$'将删除空的行。但是,如果某些行中有空格或制表符怎么办?例如,我在文本的某些部分添加了 3 个空格,如果这样做,cat -A我们会看到它显示行终止符$,但它会被偏移。

$
        mid = (lo + hi) // 2$
   $
        if x == a[mid]:$
            return x$
        if x > a[mid]:$

第二行有 3 个空格,而第一行没有。因此,我们也想使用[[:blank:]]字符类来解释这些:

$ grep -v '^[[:blank:]]*$' text.txt
           hi = len(a)  
        if lo < 0:
            raise ValueError('low must be non-negative')
        if lo == hi: 
            return None 
        mid = (lo + hi) // 2
        if x == a[mid]:
            return x
        if x > a[mid]:
            lo = mid + 1
            return self.bi_search(a, x, lo, hi)
        if x < a[mid]:
            hi = mid
            return self.bi_search(a, x, lo, hi)

现在你应该看到添加了 3 个空格的行消失了。 表示*字符重复零次或多次,因此该模式^[[:blank:]]*$还暗示了^$行中没有空格或制表符的情况。因此,此模式既可以处理真正为空的行,也可以处理看似为空的行。它也完全适用于grepsed,因为我们使用的是基本正则表达式,并且[[:blank:]]POSIX 字符类,因此它是可移植的。


我们也可以在 Python 中做类似的事情,但不使用正则表达式:

$ python3 -c 'import sys; print("\n".join([ l.rstrip() for l in sys.stdin if l.strip().split() ]))'  < text.txt
           hi = len(a)
        if lo < 0:
            raise ValueError('low must be non-negative')
        if lo == hi:
            return None
        mid = (lo + hi) // 2
        if x == a[mid]:
            return x
        if x > a[mid]:
            lo = mid + 1
            return self.bi_search(a, x, lo, hi)
        if x < a[mid]:
            hi = mid
            return self.bi_search(a, x, lo, hi)

为什么这样做有效?因为.split()字符串会在空格处拆分以提取非空格标记。如果一行仅包含空格,则结果列表.split()将为空。


正如 ilkkachu 在评论中指出的那样,如果您使用 CRLF 行尾(用于 DOS/Windows 文本文件),也会出现此问题。通过 很容易看到文件是否使用 CRLF 行尾cat -A,它们将被标记为^M。例如,

$ printf 'hello\n\r\nWorld\n   \r\ntest\n\nnewtest\n' | cat -A
hello$
^M$
World$
   ^M$
test$
$
newtest$

为了解决回车问题,可以做以下一件事:

$ printf 'hello\n\r\nWorld\n   \ntest\n\nnewtest\n' | sed '/^[[:blank:]]*\r*$/d'
hello
World
test
newtest

dos2unix可能首先使用专门为将 DOS 文件转换为 Unix 文件而设计的实用程序,然后使用sed和,这样会更简单grep。请参阅ByteCommander 的回答这显示了如何做到这一点的示例。

答案3

使用

perl -p  -e 's/^[:blank:]*$//g' inputfile | sed '/^$/d' 

你将拥有

tail -n 20 draft3.py
            hi = len(a)
        if lo < 0:
            raise ValueError('low must be non-negative')
        if lo == hi:
            return None
        mid = (lo + hi) // 2
        if x == a[mid]:
            return x
        if x > a[mid]:
            lo = mid + 1
            return self.bi_search(a, x, lo, hi)
        if x < a[mid]:
            hi = mid
            return self.bi_search(a, x, lo, hi)

只有使用 sed

sed -r 's/^[[:space:]]*$//g' inputfile | sed '/^$/d'

答案4

这个 grep 命令可以正常工作,甚至可以解释 dos 回车符、空白行、空行以及包含空格和/或制表符的空白行:

grep -v '^[[:space:]]*$'

相关内容