
Входной файл
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
Отладка вашего одного лигнера — несколько незначительных проблем:
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 '
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
'