複数行のテキストファイルを1行に並べ替える

複数行のテキストファイルを1行に並べ替える

次の形式のテキストファイルがあります。

####################################
KEY2
VAL21
VAL22
VAL23
VAL24
####################################
KEY1
VAL11
VAL12
VAL13
VAL14
####################################
KEY3
VAL31
VAL32
VAL33
VAL34

このファイルを1行ずつ並べ替え、KEY結果に次の4行を保持したいので、並べ替えられた結果は次のようになります。

####################################
KEY1
VAL11
VAL12
VAL13
VAL14
####################################
KEY2
VAL21
VAL22
VAL23
VAL24
####################################
KEY3
VAL31
VAL32
VAL33
VAL34

これを行う方法はありますか?

答え1

msort(1)複数行のレコードでファイルを並べ替えるように設計されています。これには、オプションのGUIと人が使用できる一般的なコマンドラインバージョンがあります。 (少なくともマニュアルをよく読んで例を探すのが好きな人間は...)

AFAICT、レコードに任意のパターンを使用できないため、レコードが固定サイズ (文字または行ではなくバイト単位) でない限り。実際には、空白行で区切られた行ブロックを記録するオプションがmsortあります。-b

-b各入力(最初の入力を除く)の前に空白行を追加すると、###...入力を簡単に使用できる形式に変換できます。

デフォルトでは、stderrの統計情報を印刷するので、少なくとも入力全体が単一のレコードであると思われ、ソートされていないタイミングを簡単に知ることができます。


msortあなたのデータに適用されます。 このコマンドは、行1を除く sed各行の前に改行文字を追加します。レコード全体をアルファベット順に並べ替えます。レコードのどの部分がキーとして使用されるかを選択するいくつかのオプションがありますが、必要ありません。#+-w

また、追加の改行を削除するのを見逃しました。

$ sed '2,$ s/^#\+/\n&/' unsorted.records | msort -b -w 2>/dev/null 
####################################
KEY1
VAL11
VAL12
VAL13
VAL14

####################################
KEY2
VAL21
VAL22
VAL23
VAL24

####################################
KEY3
VAL31
VAL32
VAL33
VAL34

-r '#'私はそれを記録区切り文字として使用することに幸運はありませんでした。ファイル全体をレコードと見なします。

答え2

回避策は、最初にブロック内の改行文字を未使用文字(以下の例では「|」)に変更し、結果をソートしてから、選択した区切り文字を元の改行文字に戻すことです。

sed -e 'N; N; N; N; N; s/\n/|/g' file.txt \
| sort -k2,2 -t\| \
| sed 's/|/\n/g'

答え3

perl -0ne 'print sort /(#+[^#]*)/g' file.txt
  • perl -0 全体のファイルを食べる
  • /(....)/gレコードの一致と抽出
  • print sort ...並べ替えて印刷します。

答え4

POSIX awkが利用可能標準ライブラリ:

#!/usr/local/bin/awklib -f
$0 ~ "#" {x++}
{q[x] = q[x] ? q[x] RS $0 : $0}
END {
  arr_sort(q)
  for (x in q) print q[x]
}

関連情報