(O+P)ut

アウトプット



(O+P)ut

エンジニアのアウトプット

【スクリプト/ワンライナー】複数行毎に繰り返すテキストを処理する

スポンサーリンク

はじめに

必要なデータが例えば以下のように整備されているといいのですが

textA,numA
textB,numB
...

以下のような状態であることがあります。

textA
numA
hogeA
textB
numB
hogeB
...

要は3行毎に情報が繰り返され、1行目と2行目をカンマ区切りで一行として扱いたい。これらを例にデータを整備(データクレンジング)する流れについて簡単に説明します。

コマンド実行環境
  • Debian GNU/Linux 9 (stretch)

ワンライナー

以下で3行毎のデータをCSVで扱えます。

# cat hoge.txt | awk 'ORS=NR%3?",":RS'

スクリプトでの処理方針

繰り返し部分

例えば以下のように書けば$iが1~10まで順々に値が入っていくので

for i in `seq 1 10`

3行毎の繰り返すが10セットあれば$i*3 -2でtextが、$i*3-1でnumの情報が格納されている行が取得できます。

以下のロジックを使えば特定行の数値を取れるので

例えばシェルスクリプトにて以下のようにすれば

for i in `seq 1 10`
do
        a=`expr $i \* 3 - 2`
        b=`expr $i \* 3 - 1`
        x=`cat hoge.txt | head -n $a | tail -n 1`
        y=`cat hoge.txt | head -n $b | tail -n 1`
        z=$x","$y
        echo $z
done

textA,numAといった形で出力されます。

セット数の取得部分

手動で10と入れましたが、ここもテキストによって自動的に取りたいです。
空行がない前提であれば、wl -lにて行数が取得できます。

n=`cat hoge.txt | wc -l`
m=`expr $n / 3`

for i in `seq 1 $m`
...

複数行毎に繰り返すテキストを処理するスクリプト

以下のスクリプトを実行すれば

#!/bin/bash

n=`cat hoge.txt | wc -l`
m=`expr $n / 3`

for i in `seq 1 $m`
do

        a=`expr $i \* 3 - 2`
        b=`expr $i \* 3 - 1`
        x=`cat hoge.txt | head -n $a | tail -n 1`
        y=`cat hoge.txt | head -n $b | tail -n 1`
        z=$x","$y
        echo $z
done

出力結果は以下となります。

textA,numA
textB,numB
...

終わりに

大量データの整備はシェルで捌くことが多いですが、できるだけ汎用的な方法で処理する流れを記載しました。
ご参考になれば幸いです。