回答:
ジョセフ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ソリューション)が期待どおりに機能するためには、入力ファイルの最後に空白行が必要であることを言及する価値があります。
このソリューションでは、tacとの両方を使用perlして、一度に段落を読みます。ファイル全体をメモリに読み込む必要はありません。
tac file | perl -00 -lpe '$_ = join "\n", reverse split /\n/'
ファイルのすべての行を反転し、反転した段落ごとに行を反転します。
でこれを行う方法はあるかもしれませんが、sed私はそれが簡単になるとは思えません。Perlでこれを行う方法は次のとおりです。
perl -n00e 'push @paragraphs,$_; END{print for reverse @paragraphs}' your_file
これは、入力レコード区切り文字をヌル文字(-00)として定義すると、Perlが段落モードで動作するように指示されるため機能します。Perlの段落1の定義は、定義と完全に一致します。
1見出しの下を見るOther values for $/
段落が常に単一の空行で区切られている場合:
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入力にない)ことを前提としています。
の単一のインスタンスでそれを行うことができます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/。これがないと、バックスラッシュと改行が含まれるため、リテラルのワンライナーにはなりません。)
G;h。入力制限などについて何か言及するかもしれません。
sed手元にないため、ワンライナーをテストしませんでしたが、スクリプトバージョンは段落間のギャップを確実に保持します。私はあなたの入力でそれをテストしました。スクリプトのバージョンをテストしましたか?