데이터 로깅 시스템의 1000개 파일이 포함된 디렉토리가 있는데, 각 파일은 최대 40,000줄 이상을 포함할 수 있습니다. 문제는 때때로 하나 이상의 센서에서 데이터가 기록되지 않아 손실된다는 것입니다.
파일 1:
A,B,C,D,F
10,20,10,20,5
파일 2:
B,C,D,E,F
20,10,20,5,10
파일 3:
D,E,F
10,30,20
원하는 결과는 모든 파일을 하나의 헤더로 병합/연결하는 것입니다. 입력 파일에 열이 누락된 경우(손상된 센서로 인해) 해당 섹션은 null 값으로 대체됩니다.
A,B,C,D,E,F
10,20,10,20,,5
,20,10,20,5,10
,,,10,30,20
마지막 열 F는 날짜/시간 스탬프이므로 항상 존재합니다.
이 답변을 찾았지만 모든 헤더/열이 모든 파일에서 동일하다고 가정합니다.
나도 이 문제를 발견했다여러 CSV 파일을 병합하여 일치하는 열과 일치하지 않는 열을 얻습니다.하지만 제가 사용할 수 있을 만큼 답변이 완전하지 않습니다.
감사해요
답변1
매우 깨끗하고 간단한 대안 도구를 사용해보고 싶다면(https://github.com/johnkerl/miller), 입력 CSV 파일이 포함된 폴더부터 시작하여 이 명령을 사용합니다.
mlr --csv unsparsify *.csv >out.csv
당신은 할 것
A,B,C,D,F,E
10,20,10,20,5,
,20,10,20,10,5
,,,10,20,30
F a 를 종료하려면 다음 명령을 사용하세요.
mlr --csv unsparsify then reorder -e -f F *.csv
파일이 많은 경우 다음 두 단계로 수행할 수 있습니다.
mlr --icsv cat *.csv >tmp.txt
mlr --ocsv unsparsify tmp.txt >out.csv
답변2
BEGIN {
OFS = FS = ","
# Parse given column headers and remeber their order.
# nf will be the number of fields we'd want in the output.
nf = split(pick, header)
for (i = 1; i <= nf; ++i)
order[header[i]] = i
# Output headers.
print pick
}
FNR == 1 {
# Parse column headers from input file.
delete reorder
for (i = 1; i <= NF; ++i)
# If the current header is one that we'd like to pick...
if ($i in order)
# ... record what column it is located in.
reorder[order[$i]] = i
next
}
{
# Process data fields from input file.
# We build a new output record, so explicitly split the current record
# and save it in the field array, then empty the record and rebuild.
split($0, field)
$0 = ""
for (i = 1; i <= nf; ++i)
# If reorder[i] is zero, it's a column that is not available in the
# current file.
$i = (reorder[i] == 0 ? "" : field[reorder[i]])
print
}
위 awk
스크립트는 추출하려는 열을 특정 순서로 매개변수로 선택하고 각 입력 파일에서 해당 열을 추출합니다.
질문에 표시되는 데이터의 예:
$ awk -v pick='A,B,C,D,E,F' -f script.awk file*.csv
A,B,C,D,E,F
10,20,10,20,,5
,20,10,20,5,10
,,,10,30,20
$ awk -v pick='F,B,A' -f script.awk file*.csv
F,B,A
5,20,10
10,20,
20,,
답변3
데이터 행 사이에 실제 빈 줄이 없다고 가정하고 GNU awk를 사용하여 정렬합니다.
$ cat tst.awk
BEGIN { FS=OFS="," }
FNR==1 {
delete f
for (i=1; i<=NF; i++) {
f[$i] = i
flds[$i]
}
numFiles++
next
}
{
for (tag in f) {
val[numFiles,tag] = $(f[tag])
}
}
END {
PROCINFO["sorted_in"] = "@val_str_asc"
sep = ""
for (tag in flds) {
printf "%s%s", sep, tag
sep = OFS
}
print ""
for (fileNr=1; fileNr<=numFiles; fileNr++) {
sep = ""
for (tag in flds) {
printf "%s%s", sep, val[fileNr,tag]
sep = OFS
}
print ""
}
}
.
$ awk -f tst.awk file{1..3}
A,B,C,D,E,F
10,20,10,20,,5
,20,10,20,5,10
,,,10,30,20