ファイルから複数の空白行を削除する方法は?


14

メモを作成するために使用するテキストファイルがいくつかあります-単なるプレーンテキストで、通常は単にを使用しcat >> fileます。ときどき、空白行または2行(ちょうど戻る-改行文字)を使用して、新しい主題/思考の行を指定します。各セッションの最後に、Ctrl+ Dでファイルを閉じる前に、通常、セッションを分離するためだけに多く(5〜10)の空白行(リターンキー)を追加します。

これは明らかにあまり賢いものではありませんが、この目的には役立ちます。しかし、私たくさんの不要な空白行で終わるので、余分な行(のほとんど)を削除する方法を探しています。いくつかのオプションで直接使用できるLinuxコマンド(カット、貼り付け、grep、...?)はありますか?また、誰かがsed、awkまたはperl(私はsedまたはawkが好きですが、実際にはスクリプト言語でも)のスクリプトを考えていますか?C ++で何かを書く(実際に自分でできる)のは、やり過ぎのように思えます。

ケース#1:必要なのは、連続する2行以上(3行以上)の空白行を削除し、それらを2行だけの空白行に置き換えるスクリプト/コマンドです。ただし、複数の行(2行以上)を削除したり、複数の空白行を1つの空白行に置き換えたりできるように調整できると便利です。

ケース#2:2行のテキスト間の単一の空白行を削除するスクリプト/コマンドを使用することもできますが、複数の空白行をそのまま残します(ただし、空白行の1つを削除してもかまいません)。



2
@ l0b0、それはまったく別の質問です(もう1つはvim1つで、空白行を1つの空白行に置き換えることでした)。
ステファンシャゼル

回答:


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}'

sedではなくawkの+1
ロブ

このユースケースは頻繁に繰り返されるため、スクリプトを作成することをお勧めします。
ChuckCottrill

15

uniq空白行の複数のインスタンスを1つの空白行に折りたたむことができますが、テキストが同じで互いに下にある場合は、テキストを含む行も折りたたまれます。


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/'

つまり、パターンスペースで空の行を収集し、3行以上ある場合は2行に減らします。

ケース#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

「uniq」を使用するというAnthonの提案に従って...

先頭、末尾、重複する空白行を削除します。

# 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//"

1つの長い行で:

(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」を使用します。

より効率的だと思われる現在のシェルコンテキストを維持するために、括弧から中括弧に切り替えました。中括弧には、最後のコマンドの後にセミコロンが必要であり、分離のためのスペースが必要であることに注意してください。

# 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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.