ファイル内の段落の順序を逆にする


8

段落内のテキスト(テキストが1つ以上の空行で区切られている行)を含むファイルがあります。できればsedを使用して、段落の順序を逆にしたい(つまり、最後の段落が最初になる...)。

私は、段落のファイルに対して行われるsedコマンドtac、行のファイルに対して行われるものを探しています。

回答:


6

ジョセフRがsed述べているように、使用するのは簡単ではありません。ただし、次のように言うことができます。

sed '/./{H;d;};x;s/\n/={NL}=/g' inputfile | \
sed -e 's/^={NL}=//' -e '1!G;h;$!d' | \
sed G | sed 's/={NL}=/\'$'\n/g'

サンプル入力が与えられた場合:

Para 1 line 1
Para 1 line 2
Para 1 line 3

Para 2 line 1
Para 2 line 2
Para 2 line 3

Para 3 line 1
Para 3 line 2
Para 3 line 3

これは以下を生成します:

Para 3 line 1
Para 3 line 2
Para 3 line 3

Para 2 line 1
Para 2 line 2
Para 2 line 3

Para 1 line 1
Para 1 line 2
Para 1 line 3

このソリューション(および代替のPerlソリューション)が期待どおりに機能するためには、入力ファイルの最後に空白行が必要であることを言及する価値があります。


6

このソリューションでは、tacとの両方を使用perlして、一度に段落を読みます。ファイル全体をメモリに読み込む必要はありません。

tac file | perl -00 -lpe '$_ = join "\n", reverse split /\n/'

ファイルのすべての行を反転し、反転した段落ごとに行を反転します。


これは非常にエレガントで効率的です。ただし、このソリューションは、複数の空の(つまり、分離している)行を1つに凝縮します
Martin Vegter

3

でこれを行う方法はあるかもしれませんが、sed私はそれが簡単になるとは思えません。Perlでこれを行う方法は次のとおりです。

perl -n00e 'push @paragraphs,$_; END{print for reverse @paragraphs}' your_file

これは、入力レコード区切り文字をヌル文字(-00)として定義すると、Perlが段落モードで動作するように指示されるため機能します。Perlの段落1の定義は、定義と完全に一致します。


1見出しの下を見るOther values for $/


これは確かに機能します。唯一の小さな問題は、段落を区切る複数の空行を保持しないことです。代わりに、すべての段落が1行の空行で区切られます。
Martin Vegter 14

1

段落が常に単一の空行で区切られている場合:

sed '/^$/s/^/\x02/' infile | tr \\n$'\002' $'\003'\\n | \
sed 's/^\x03//;1s/\x03$//;1!G;h;$!d;$a\' | tr $'\003' \\n

それはあなたが粉々にそれを破ると、実行した場合、それがどのように動作するかを確認するためには非常に簡単です sed '/^$/s/^/\x02/' infile、その後sed '/^$/s/^/\x02/' infile | tr \\n$'\002' $'\003'\\nのように...


段落が1行以上の空行で区切られている場合、たとえば

Para 1 line 1
Para 1 line 2

Para 2 line 1


Para 3 line 1
Para 3 line 2

Para 4 line 1
Para 4 line 2



Para 5 line 1

そして、段落の順序を逆にして「空のブロック」の順序を維持したい場合は、ファイルを2回読み取ることができます
。1番目:段落を1行にして(その間に空のブロックを削除)、それらを逆にし、
2番目:空のブロックをオンにします。単一の行に、「インデクシング」は、各ブロック内の空行の数(および非空行を除去する)
、次いでpaste結果と改行を復元するための出力を処理します。

paste -d $'\004' <(sed '/^$/s/^/\x02/' infile | tr \\n$'\002' $'\003'\\n | \
sed -e '/^\x03$/d;s/^\x03//;s/\x03$//;1!G;h;$!d;$a\') \
<(sed -E '/^$/!d;//{:a;N;/^(\n){1,}$/ba;s/\n/\x02/g;s/(.*)\x02.*/\1/}' infile) \
| sed '$!s/\x04/\n/;$s/\x04$//' | tr $'\003\002' \\n\\n

出力:

Para 5 line 1

Para 4 line 1
Para 4 line 2


Para 3 line 1
Para 3 line 2

Para 2 line 1



Para 1 line 1
Para 1 line 2

出力の余分な末尾行を気にしない場合は、最後を削除できますsed

paste -d $'\n' <(sed '/^$/s/^/\x02/' infile | tr \\n$'\002' $'\003'\\n | \
sed -e '/^\x03$/d;s/^\x03//;s/\x03$//;1!G;h;$!d;$a\') \
<(sed -E '/^$/!d;//{:a;N;/^(\n){1,}$/ba;s/\n/\x02/g;s/(.*)\x02.*/\1/}' infile) | \
tr $'\003\002' \\n\\n

これらは、最初と最後の行が空ではない(そして\x02\x03または\x04入力にない)ことを前提としています。


1

の単一のインスタンスでそれを行うことができますsed。パイプは必要ありません。ためsedだけ文書をワンパスを行い、として必要なファイルの一部ので初め出力はであるファイルの、メモリ内部にファイル全体を保持する必要がありますsed、それはよい-SO(ホールド空間内)うまくスケーリングしない。しかし、それは質問に正確に答えます:

:getpara
   ${
      s/$/\
/
      G
      s/\n\n$//
      q
   }
   N
   /\n$/!bgetpara
G
h
$!d
s/\n\n$//
q

後続の改行がない場合でも、これは正常に機能します。末尾の改行が1つしかない場合、出力では抑制されます(つまり、出力の先頭の改行はありません)。(たとえば)入力に5つの後続改行がある場合、出力には4つの先行改行があります。

段落間のギャップは保持されます。

それ以外の場合は空の行にある空白は段落区切りとして扱われませんが、それはバグではなく機能です。:)

読みにくいワンライナーとしてこれを行うこともできます:

sed ':k;${;s/\(\(\n\).*\)$/\1\2/;G;s/\n\n$//;q;};N;/\n$/!bk;G;h;$!d;s/\n\n$//;q' inputfile

これはGNUでのみ機能しますがsed。(を実行するための後方参照のトリッキーな使用に注意してくださいs/$/\n/。これがないと、バックスラッシュと改行が含まれるため、リテラルのワンライナーにはなりません。)


ファイルを丸呑みにしますよね?全体をホールドスペースに入れているようです。w / G;h。入力制限などについて何か言及するかもしれません。
mikeserv 2015年

私はMacで作業していて、GNUがsed手元にないため、ワンライナーをテストしませんでしたが、スクリプトバージョンは段落間のギャップを確実に保持します。私はあなたの入力でそれをテストしました。スクリプトのバージョンをテストしましたか?
ワイルドカード

@mikeserv:確かにそうです。(今夜更新されます。)
ワイルドカード

0
gem install facets

ruby -r facets/string \
     -e 'puts $stdin.read.strip.shatter(/\n\n+/).reverse.join("")' < file

これは段落の間隔を維持するはずです(sed:) よりも読みやすくなります)けれども、すばらしい答えを得るためにdevnullするための小道具があります。

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