입력 파일
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"
, 6개의 필드가 있습니다 ""
. 첫 번째 필드 앞에 필드가 하나 있고 <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
'