
輸入檔
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
調試你的一個 ligner ——幾個小問題:
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 列,第 2 列中的值將變為第 1 列。
透過我們的/ +/
分隔符號正規表示式,我們可以獲得真正的分隔行為。帶有前導空格和尾隨空格的記錄1 2 3 4
被視為<SEP>1<SEP>2<SEP>3<SEP>4<SEP>
。因此有六個字段:""
, "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
'