
入力ファイル
CARD SG CLASS ATT
11 0 DAS YES
CARD SG CLASS ATT
12 0 ECT YES
CARD SG CLASS ATT
13 0 VAS YES
1 DAS NO
CARD SG CLASS ATT
14 0 SAT YES
CARD SG CLASS ATT
15 0 CDT YES
1 VEG YES
2 GAT NO
予想される出力:
CARD SG CLASS ATT
11 0 DAS YES
12 0 ECT YES
13 0 VAS YES
13 1 DAS NO
14 0 SAT YES
15 0 CDT YES
15 1 VEG YES
15 2 GAT NO
私がしたこと:
awk ' /YES|NO/{VAL=$1};/ATT/{Print "CARD" "SG" "CLASS" "ATT" };/YES|NO/{ print VAL, $2, $3, $4} ' SCGR.txt | column -t
11 0 DAS YES
12 0 ECT YES
13 0 VAS YES
1 DAS NO
14 0 SAT YES
15 0 CDT YES
1 VEG YES
2 GAT NO
助けてください
答え1
これを試してください(すべてのヘッダー行が正確に等しいと仮定します)。
awk ' NR==1{header=$0; count=NF; print; next}
($0~header) {next}
(NF==count) {col1=$1}
(NF<count) {printf("%s",col1)}
1 ' infile | column -t
答え2
1 つのライナーのデバッグ - いくつかの小さな問題:
Print
--print
/ATT/{Print "CARD" "SG" "CLASS" "ATT" }
-/ATT/{print}
または/ATT/;
/YES|NO/{VAL=$1}
3つのフィールドレコードでもトリガーされ、以前に保存された値が消去されます。(順序を変更するか、$4 ~ /YES|NO/
)
バリエーション:
awk 'NF==4{v=$1;print} NF==3{print v,$0}'
余分なヘッダーとインデントを削除します。
awk '/^CARD/ && NR>1 { next }
NF==4 { v=$1;print }
NF==3 { print v,$0 }'
答え3
列の配置を気にせず、空白で区切られた正規化されたデータだけが必要な場合、基本的なパターンは次のようになります。
awk -F' +' '{ $1 = ($1 ~ /^$/ ? prev : $1); prev = $1; print }'
デフォルトのスペースと等しくないカスタム フィールド セパレーターを設定すると、フィールドの真の分離が実現されます。レコードがセパレーターに一致する文字で始まる場合、空のフィールドが区切られます。
デフォルトでは、Awk は分離せず、トークン化します。つまり、各レコードから 1 つ以上の非空白/非改行文字のシーケンスであるトークンを抽出します。つまり、先頭と末尾の空白/改行は無視されます。したがって、列 1 が欠落している場合は、列 2 の値が列 1 になります。
セパレータ正規表現を使用すると/ +/
、真の分離動作が得られます。 のような先頭と末尾のスペースを含むレコードは1 2 3 4
として扱われます<SEP>1<SEP>2<SEP>3<SEP>4<SEP>
。したがって、、、...、、の 6 つのフィールドがあります。""
最初"1"
の"4"
フィールドの前と最後のフィールドの後に""
フィールドがあります。<SEP>
ところで、最初のレコードにフィールドが欠落している可能性がある場合は、 のデフォルトが必要であることは明らかですprev
。また、見出しにロジックを適用したくありません。また、三項演算子を : に置き換えてみましょうif
。つまり、次のようになります。
awk 'BEGIN { FS = " +"; prev = 0 }
NR == 1
NR > 1 { if ($1 == "") $1 = prev
print
prev = $1 }'
FOO BAR BAZ
FOO BAR BAZ
2 3 4
0 2 3 4
1 2 3 4
1 2 3 4
2 3 4
1 2 3 4
答え4
教育のためだけにsedの決定
sed '
1b #output 1st line (header)
$!N #add next line to operate 2 lines altogether
s/\(.*\)\n\(CARD.*\)/\2\n\1/ #move line with CARD to first place
/^CARD/D #delete line with CARD and go to start
s/^\(\([0-9]*\s*\).*\n\)\s\s*/\1\2/
#repeat 1st field of 1st line if empty in 2nd
/\n/{P;D} #print&remove 1st line, go to start
'