前の行に基づいて行を更新する

前の行に基づいて行を更新する

私は awk に慣れていないので、問題があります。sar -d 出力から生成された csv ファイルを csv スタイルに変換しました:

12:33:41        unix,restarts
12:35:00,lofi4096,0,0.0,0,0,0.0,0.0
,iscsi0,0,0.0,0,0,0.0,0.0
,scsi_vhc,0,0.0,0,0,0.0,0.0
,nfs1,0,0.0,0,0,0.0,0.0

12:45:00,lofi4096,0,0.0,0,0,0.0,0.0
,iscsi0,0,0.0,0,0,0.0,0.0
,scsi_vhc,0,0.0,0,0,0.0,0.0
,nfs1,0,0.0,0,0,0.0,0.0

そして私はこれに変換したい

12:33:41        unix,restarts
12:35:00,lofi4096,0,0.0,0,0,0.0,0.0
12:35:00,iscsi0,0,0.0,0,0,0.0,0.0
12:35:00,scsi_vhc,0,0.0,0,0,0.0,0.0
12:35:00,nfs1,0,0.0,0,0,0.0,0.0

12:45:00,lofi4096,0,0.0,0,0,0.0,0.0
12:45:00,iscsi0,0,0.0,0,0,0.0,0.0
12:45:00,scsi_vhc,0,0.0,0,0,0.0,0.0
12:45:00,nfs1,0,0.0,0,0,0.0,0.0

試してみましたが、awk は行ごとに読み取るため、前の行の値を保持する方法がわかりません。私が持っているものは機能するはずです。希望する結果を得るにはどうすればよいか、何かアイデアはありますか。awk で試しましたが、sed またはカスタム シェル スクリプトを使用した難しい方法 (この部分は避けようとしています) で可能になると思います。

#!/usr/bin/awk -f
BEGIN {
        FS=",";
}
{
        print $1
        if ($1 != "") {
                mydate=$1;
                print $0;
        }
        else {
                print $mydate","$0;
        }
}

Solaris 11.1 でシステムを実行しています。

答え1

入力に空白行があるようなので、少し長くなります。次の方法が役に立つかもしれません:

awk -F'[, ]' '{if (NF!=0 && $1=="") {$1=prev} prev=$1}1' OFS=, inputfile

アイデアは、フィールドを,空白で分割することです(後者は入力の最初の行を処理するためです)。最初のフィールドが空白かどうかを確認します。そしてフィールド数がゼロでない場合(空白行を処理する)、最初のフィールドを以前に保存した最初のフィールドに置き換えます。

入力すると、次のものが生成されます:

12:33:41        unix,restarts
12:35:00,lofi4096,0,0.0,0,0,0.0,0.0
12:35:00,iscsi0,0,0.0,0,0,0.0,0.0
12:35:00,scsi_vhc,0,0.0,0,0,0.0,0.0
12:35:00,nfs1,0,0.0,0,0,0.0,0.0

12:45:00,lofi4096,0,0.0,0,0,0.0,0.0
12:45:00,iscsi0,0,0.0,0,0,0.0,0.0
12:45:00,scsi_vhc,0,0.0,0,0,0.0,0.0
12:45:00,nfs1,0,0.0,0,0,0.0,0.0

答え2

sed

sed '/^[0-9]/{               # if line starts with digit
h                            # overwrite hold buffer with pattern space content
s/\([^,]*\),.*/\1/           # extract timestamp
x                            # exchange: put the original line back into pattern
}                            # space and the timestamp in hold space
/^,/{                        # if line starts with a comma
G                            # append hold space (timestamp) to pattern space
s/\(.*\)\n\(.*\)/\2\1/       # swap the initial line content and the timestamp 
}' infile

一行で:

sed -e'/^[0-9]/{h;s/\([^,]*\),.*/\1/;x' -e\} -e'/^,/{G;s/\(.*\)\n\(.*\)/\2\1/' -e\} infile

答え3

別のsed

sed '$!N;/\n,/s/\([^,]*\).*\n/&\1/;P;D' <in >out

!最後ではない各入力行について$、ext 入力行を ewline 文字の後に続くパターン スペースにsed追加します。次に、 ewline の直後のコンマの直前のスペースに、コンマ以外の文字の最初の可能なグループをコピーする置換を試みます。それができない場合は、まあ、害はないと思います。N\ns///^,\n

sed次に、パターン空間のP最初の ewline まで出力し、同じ行を削除してから、次の入力行のペアで最初から新たにサイクルを開始します。\nD

出力

12:33:41        unix,restarts
12:35:00,lofi4096,0,0.0,0,0,0.0,0.0
12:35:00,iscsi0,0,0.0,0,0,0.0,0.0
12:35:00,scsi_vhc,0,0.0,0,0,0.0,0.0
12:35:00,nfs1,0,0.0,0,0,0.0,0.0

12:45:00,lofi4096,0,0.0,0,0,0.0,0.0
12:45:00,iscsi0,0,0.0,0,0,0.0,0.0
12:45:00,scsi_vhc,0,0.0,0,0,0.0,0.0
12:45:00,nfs1,0,0.0,0,0,0.0,0.0

関連情報