次の形式のテキストファイルがあります。
####################################
KEY2
VAL21
VAL22
VAL23
VAL24
####################################
KEY1
VAL11
VAL12
VAL13
VAL14
####################################
KEY3
VAL31
VAL32
VAL33
VAL34
このファイルをKEY
行で並べ替え、次の4行を結果に含めたいので、並べ替えた結果は次のようになります。
####################################
KEY1
VAL11
VAL12
VAL13
VAL14
####################################
KEY2
VAL21
VAL22
VAL23
VAL24
####################################
KEY3
VAL31
VAL32
VAL33
VAL34
これを行う方法はありますか?
msort(1)
は、複数行のレコードを含むファイルをソートできるように設計されています。オプションのGUIと、通常の人間が使用できるコマンドラインバージョンがあります。 (少なくとも、マニュアルを注意深く読み、例を探すのが好きな人間...)
AFAICT、レコードに任意のパターンを使用することはできないため、レコードが固定サイズ(文字または行ではなくバイト単位)でない限り。 msort
には、空白行で区切られた行のブロックであるレコードの-b
オプションがあります。
入力を、すべての-b
(最初の行を除く)の前に空白行を置くことで、###...
で簡単に機能する形式に変換できます。
デフォルトでは、stderrに統計情報を出力するため、少なくとも入力全体が単一のレコードであると考えられていたため、ソートされなかった場合は簡単に判別できます。
msort
はデータに対して機能します。sed
コマンドは、以下を除くすべての#+
行に改行を追加します1行目。-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 '#'
を使用してレコードセパレーターとして使用することはできませんでした。ファイル全体が1つのレコードであると考えていました。
解決策は、まずブロック内の改行を選択した未使用の文字(以下の例では '|')に変更し、結果を並べ替え、選択したセパレーターを元の改行に戻すことです。
sed -e 'N; N; N; N; N; s/\n/|/g' file.txt \
| sort -k2,2 -t\| \
| sed 's/|/\n/g'
_Perl -0ne 'print sort /(#+[^#]*)/g' file.txt
_
Perl -0
_ファイル全体を丸呑みします/(....)/g
レコードを照合して抽出するprint sort ...
_並べ替えて出力するKEY
セクションの任意の数の行を処理する別の方法を次に示します。
# extract delimiter
delim=$(head -n1 <infile)
sed '/#/d;/KEY/h;G;s/\n/\x02/' infile | nl -ba -nrz -s $'\002' | sort -t $'\002' -k3 -k1,1 |
cut -d $'\002' -f2 | sed '/KEY/{x;s/.*/'"${delim}"'/;G}'
これは、区切り文字を変数に保存することで機能します(その後、入力から削除します)。次に、KEY*
を対応するセクションの各行に、低ASCII文字(入力では発生しそうにありません)を区切り文字として使用し、次にn
umbersすべてのl
inesを使用して追加します。同じセパレータ。その場合は、3番目と1番目のフィールドをsort
ingし、中央の列をcut
tingし、最後のsed
を使用して区切り文字を復元するだけです。上記の場合、KEY12
はKEY2
の前にソートされるので、必要に応じてsort
コマンドを調整してください。
POSIX Awk stdlibライブラリ を使用できます。
#!/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]
}