행 값을 열 값으로 변환하는 데 도움을 주세요. 내 입력은 file.dat
다음과 같습니다
처음 두 필드는 각각 알파벳 문자열과 숫자입니다. 입력에는 항상 동일한 수의 필드가 있습니다.6.
입력하다
A|1|DLT|07:30|10:30|34
A|1|STG|07:30|10:30|NA
A|1|MAIN|06:30|10:30|NA
A|2|STG|07:30|10:30|NA
A|2|UNLD|04:30|10:30|90
B|1|DLT|03:30|10:30|34
B|1|STG|07:30|09:30|NA
B|1|MAIN|07:25|10:30|NA
B|1|UNLD|05:30|12:30|8
출력에 변화가 있습니다. 출력 필드 모든 줄에는 18개의 필드가 있으며 각 줄에는 입력 파일의 처음 두 필드가 있고 그 뒤에는 다음 순서로 3번째, ..., 18번째 필드가 있습니다. 여기서 빈 필드는 입력 파일에서 누락된 줄입니다. 레코드 순서는 DLT이며 STG, MAIN 및 UNLD 뒤에 해당 레코드가 있습니다.
산출
A|1|DLT|07:30|10:30|34|STG|07:30|10:30|NA|MAIN|06:30|10:30|NA||||
A|2|||||STG|07:30|10:30|NA|||||UNLD|04:30|10:30|90
B|1|DLT|03:30|10:30|34|STG|07:30|09:30|NA|MAIN|07:25|10:30|NA|UNLD|05:30|12:30|8
- A|1 UNLD 누락
- A|2에는 DLT 및 MAIN이 없습니다.
- 기록이 손실되지 않습니다.
마찬가지로 입력 파일의 세 번째 필드에 해당하는 레코드가 누락된 경우 출력 필드가 다음과 같이 되도록 빈 값으로 바꿔야 합니다.18개 지역.
답변1
나의 awk
충고:
awk -F'|' '{ if (a[$1$2] == "") {
a[$1$2] = $0
}
else {
a[$1$2] = a[$1$2]","$3"|"$4"|"$5"|"$6
}
}
END {
for (key in a) {
print a[key]
}
}' <input.txt | sort
설명하다
이 -F'|'
옵션은 정의합니다필드 구분 기호( awk
줄의 필드를 구문 분석하는 데 사용됨)은 파일 형식이므로 문자 "|"로 사용됩니다.
a[...]
배열입니다. 배열은 awk
인덱스가 아닌 Python 사전과 다소 비슷합니다.열쇠이것은 실제로 문자열입니다. 입력 파일의 각 줄에 대해 테스트에서는 항목이 있는 경우 처음 2개 필드(예: 첫 번째 줄) if (a[$1$2] == "")
에 해당하는 키를 확인합니다. $1$2 = A1
그렇지 않은 경우( A|1|...
첫 번째 행을 읽음) 전체 행이 이 키( a[$1$2] = $0
)에 저장됩니다. 이미 콘텐츠가 있는 경우( A|1|...
다른 행이 저장됨) 항목을 쉼표로 연결하고 "|"를 사용하여 필드를 3에서 6까지 구분합니다. ( a[$1$2] = a[$1$2]","$3"|"$4"|"$5"|"$6
).
마지막으로 파일 탐색이 끝나면 각 키에 대한 항목을 출력해야 합니다. 우리는 END
이 작업을 블록에서 수행합니다(이 명령은 모든 파일을 읽은 후에 실행됩니다). 이를 위해 for (key in a)
배열( )의 모든 키를 반복 하고 각 키에 대한 항목을 인쇄합니다.
그런 다음 최종 출력은 으로 파이프됩니다 sort
. 배열 키는 영숫자로 순회되지 않기 때문에 나중에 행 등을 awk
얻을 수 있도록 출력을 정렬하는 것이 더 깔끔할 것입니다 .A|1|...
A|2|...
마지막 편집으로 인해 모든 것이 약간 까다로워졌습니다. 필요한 지침이 awk
다소 복잡해질 수 있으므로 스크립트 파일을 생성하는 것이 좋습니다(예: 확장자를 가진 텍스트 파일 생성 awk
). 다음 스크립트를 복사하세요..awk
myScript.awk
BEGIN { FS="|" }
$3 == "DLT" {
dlt[$1"|"$2]=$3"|"$4"|"$5"|"$6
a[$1"|"$2]++
}
$3 == "STG" {
stg[$1"|"$2]=$3"|"$4"|"$5"|"$6
a[$1"|"$2]++
}
$3 == "MAIN" {
main[$1"|"$2]=$3"|"$4"|"$5"|"$6
a[$1"|"$2]++
}
$3 == "UNLD" {
unld[$1"|"$2]=$3"|"$4"|"$5"|"$6
a[$1"|"$2]++
}
END {
for (key in a) {
if (dlt[key] == "") dlt[key]="|||"
if (stg[key] == "") stg[key]="|||"
if (main[key] == "") main[key]="|||"
if (unld[key] == "") unld[key]="|||"
print key"|"dlt[key]"|"stg[key]"|"main[key]"|"unld[key]
}
}
그걸 써:
awk -f myScript.awk <input.txt | sort
내 원래 답변에 대한 설명을 이해했다면 이 알고리즘도 이해할 수 있을 것입니다. 이번에는 각 데이터 유형(dlt, stg, main 및 unld)에 대한 배열을 만들고 해당 값을 처음 두 필드에 해당하는 키에 저장합니다. " " 배열은 a
가능한 모든 키를 추적하는 데 사용됩니다. 마지막으로 배열의 키를 반복 a
하고 해당 키에서 데이터 배열 중 하나가 비어 있으면 원하는 대로 "|||"를 채워 각 행에 18개의 필드가 있습니다.
답변2
약간 다른발렌타인 B.의 답변:
awk -F"|" '
{
key = $1 "|" $2
a[key] = 1
b[key][$3] = $3 "|" $4 "|" $5 "|" $6
}
END {
subtype[1] = "DLT"
subtype[2] = "STG"
subtype[3] = "MAIN"
subtype[4] = "UNLD"
for (key in a)
{
output = key
for (i = 1; i <= 4; i++)
{
st = subtype[i]
if (b[key][st] == "")
output = output "||||"
else
output = output "|" b[key][st]
}
print output
}
}' file.dat
에서와 같이발렌타인 B.의 답변:
-F"|"
|
입력 행에서 필드를 추출할 수 있도록 필드 구분 기호를 로 설정합니다 .key
A|1
,A|2
또는B|1
또는 일반적으로 처음 두 필드의 연결 로 설정합니다 . 이를 사용하여 해당 키 조합과 관련된 데이터의 최대 4개 행을 결합합니다.a[key]
우리가 보는 데이터(키)를 기록하려면 1로 설정합니다 .b[key][$3]
키 뒤의 나머지 줄로 설정합니다 . 예를 들어b["A|1"]["DLT"]
는 로 설정됩니다"DLT|07:30|10:30|34"
. 이런 식으로 우리는 로그를 남길 수 있습니다.모두우리가 보는 데이터(질문에 지정된 대로 행에 6개 이하의 필드가 있다고 가정) 에 무엇이 포함될지 모르고 이 작업을 수행한다는 점에 유의하세요$3
.
모든 데이터를 읽은 후:
- 하위 유형(예: 유효한 값, "DLT", "STG", "MAIN" 및 "UNLD")을 정의하는 배열
$3
이므로 하위 유형을 여러 번 나열할 필요가 없습니다. - 우리가 본 모든 키를 반복합니다. 출력 라인 구축을 시작하십시오.
- 위에 나열된 네 가지 하위 유형을 반복합니다. 해당 키와 해당 하위 유형에 대한 데이터가 있으면 이를 출력 행에 추가하고, 그렇지 않으면 4개의 빈 필드를 추가합니다.
- 이 줄을 인쇄하세요.
sort
출력을 정렬하려면 파이프로 연결하십시오. (내가 "만약"이라고 말한 이유는, 비록 질문은프로그램예제 출력은 정렬되어 있지만 이것이 출력을 정렬해야 한다는 의미는 아닙니다. )
두 번째 필드에 무엇이 있는지에 대한 질문은 정확하지 않습니다. 단지 "숫자"라고만 나와 있습니다. 숫자가 다른 정수일 수 있고 숫자로 정렬하려면 다음을 사용하십시오.
sort -t"|" -k1,1 -k2,2n
답변3
네 번째 필드의 값을 캡처하여 "val"이라는 변수에 저장합니다.
배열을 생성하고 첫 번째 및 두 번째 필드를 기반으로 배열의 값을 추가합니다.
마지막으로 배열 값을 인쇄하고 작은 조정(교체, 삭제 등)을 합니다.
$ awk -F\| '{ val=$3;
for (i=4;i<=NF;i++) {val=val"|"$i}
Arr[$1OFS$2]=Arr[$1OFS$2]","val;
next
}
END { for (i in Arr) {
A=Arr[i];
sub(" ","|",i);
print i,A
}
}' test.txt | sed "s/ ,/\|/"
A|1|DLT|07:30|10:30|34 ,STG|07:30|10:30|NA ,MAIN|06:30|10:30|NA
B|1|DLT|03:30|10:30|34 ,STG|07:30|09:30|NA ,MAIN|07:25|10:30|NA ,UNLD|05:30|12:30|8
A|2|UNLD|04:30|10:30|90 ,DLT|08:30|11:30|4 ,STG|07:30|10:30|NA