如何从文件中删除多个空白行?


14

我有一些用于记笔记的文本文件-纯文本,通常仅使用cat >> file。有时我使用一两行空白(仅返回-换行符)来指定新的主题/思路。在每个会话结束时,在用Ctrl+ 关闭文件之前D,我通常添加很多(5-10)空行(返回键)以分隔会话。

这显然不是很聪明,但是它对我有用。我不过最终了很多很多不必要的空行,所以我在寻找一种方式来删除(大部分)的额外线。是否有Linux命令(剪切,粘贴,grep,...?)可以直接与几个选项一起使用?或者,是否有人对sed,awk或perl(可以在任何脚本语言中使用,尽管我更喜欢sed或awk)的脚本都能满足我的需求?用C ++编写某些东西(我实际上可以自己做),似乎有点过头了。

情况1:我需要的是一个脚本/命令,该脚本/命令将删除多于两个(3个或更多)连续的空行,并将其替换为仅两个空行。尽管也可以对其进行调整以删除多于一行(两行或更多)和/或仅用一个空白行替换多个空白行,这是很好的。

情况2:我还可以使用脚本/命令来删除两行文本之间的单个空白行,但照原样保留多个空白行(尽管删除其中一个空白行也是可以接受的)。



2
@ l0b0,这是一个完全不同的问题(另一个是vim一个问题,用一个空行替换空行)。
斯特凡Chazelas

Answers:


14

情况1:

awk '!NF {if (++n <= 2) print; next}; {n=0;print}'

情况2:

awk '!NF {s = s $0 "\n"; n++; next}
     {if (n>1) printf "%s", s; n=0; s=""; print}
     END {if (n>1) printf "%s", s}'

awk而不是sed +1
Rob

由于该用例经常重复,因此建议创建一个脚本。
ChuckCottrill

15

您可以用来uniq将多个空行实例折叠为一个空行,但是如果它们相同且位于彼此下方,也可以折叠包含文本的行。


6

情况1:

perl -i -ane '$n=(@F==0) ? $n+1 : 0; print if $n<=2'

情况2:

perl -i -ane '$n=(@F==0) ? $n+1 : 0; print $n==2 ? "\n$_" : $n==1 ? "" : $_ '

+1 perl ftw!Awk(可能)对此是规范的,但是(DRY)强迫我为这样重复的用例编写脚本。
ChuckCottrill

3

您可以使用GNU sed这样处理案例1:

sed -r ':a; /^\s*$/ {N;ba}; s/( *\n *){2,}/\n\n/'

即,在模式空间中收集空行,如果多于三行或更多行,则将其减少为两行。

要连接单行,如案例2所示,您可以这样操作:

sed -r '/^ *\S/!b; N; /\n *$/!b; N; /\S *$/!b; s/\n *\n/\n/'

或以评论形式:

sed -r '
  /^ *\S/!b        # non-empty line
  N                # 
  /\n *$/!b        # followed by empty line
  N                # 
  /\S *$/!b        # non-empty line
  s/\n *\n/\n/     # remove the empty line
'

1

此解决方案还照顾文件中的最后空白行:

sed -r -n '
  /^ *$/!{p;b}  # non-blank line - print and next cycle
  h             # blank line - save it in hold space
  :loop
  $b end        # last line - go to end
  n             # read next line in pattern space
  /^ *$/b loop  # blank line - loop to next one
  :end          # pattern space has non-blank line or last blank line
  /^ *$/{p;b}   # last blank line: print and exit
  H;x;p         # non-blank line: print hold + pattern space and next cycle
'

0

遵循Anthon的建议使用“ uniq” ...

删除开头,结尾和重复的空白行。

# Get large random string.
rand_str=; while [[ ${#rand_str} -lt 40 ]]; do rand_str=$rand_str$RANDOM; done

# Add extra lines at beginning and end of stdin.
(echo $rand_str; cat; echo $rand_str) |

# Convert empty lines to random strings.
sed "s/^$/$rand_str/" |

# Remove duplicate lines.
uniq |

# Remove first and last line.
sed '1d;$d' |

# Convert random strings to empty lines.
sed "s/$rand_str//"

长行中:

(rand_str=; while [[ ${#rand_str} -lt 40 ]]; do rand_str=$rand_str$RANDOM; done; (echo $rand_str; cat; echo $rand_str) | sed "s/^$/$rand_str/" | uniq | sed '1d;$d' | sed "s/$rand_str//")

或者只使用“ cat -s”。

我从括号改为大括号,以便保留在当前的shell上下文中,我认为这样更有效。请注意,花括号在最后一个命令后需要用分号分隔,并且需要一个空格。

# Add extra blank lines at beginning and end.
# These will be removed in final step.
{ echo; cat; echo; } |

# Replace multiple blank lines with a single blank line.
cat -s |

# Remove first and last line.
sed '1d;$d'

在一行中。

{ { echo; cat; echo; } | cat -s | sed '1d;$d'; }

0

对我来说,发布的解决方案看起来有些神秘。这是Python 3.6中的解决方案:

#!/usr/bin/env python3

from pathlib import Path                                                                                                                                                              
import sys                                                                                                                                                                            
import fileinput                                                                                                                                                                      


def remove_multiple_blank_lines_from_file(path, strip_right=True): 
    non_blank_lines_out_of_two_last_lines = [True, True] 
    for line in fileinput.input(str(path), inplace=True): 
        non_blank_lines_out_of_two_last_lines.pop(0) 
        non_blank_lines_out_of_two_last_lines.append(bool(line.strip())) 
        if sum(non_blank_lines_out_of_two_last_lines) > 0: 
            line_to_write = line.rstrip() + '\n' if strip_right else line 
            sys.stdout.write(line_to_write)


def remove_multiple_blank_lines_by_glob(rglob='*', path=Path('.'), strip_right=True): 
    for p in path.rglob(rglob): 
        if p.is_file(): 
            try:
                remove_multiple_blank_lines_from_file(p, strip_right=strip_right)
            except Exception as e:
                print(f"File '{p}' was not processed due the error: {e}")


if __name__ == '__main__':
    remove_multiple_blank_lines_by_glob(sys.argv[1], Path(sys.argv[2]), next(iter(sys.argv[3:]), None) == '--strip-right')

您可以从解释器调用函数,也可以从外壳运行它,例如:

$ ./remove_multiple_lines.py '*' /tmp/ --strip-right
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.