awk를 사용하여 항목을 스프레드시트(csv)로 구성

awk를 사용하여 항목을 스프레드시트(csv)로 구성

항목(N=1000)에 대한 정보를 항목당 구분된 텍스트 파일(각 항목당 하나의 텍스트 파일)로 내 컴퓨터에 저장합니다. 기록되는 정보 형식은 다음과 같습니다.

============
NAME: Matty Nigan
Age: 65 
Sex: M
Weight: XX
TIME: 12:31:25
Home address: XXXXX
Phone number: XXX XXX XXXX
============

다음과 같이 이러한 항목(N=1000)에서 모든 데이터를 수집하고 구성하고 싶습니다.

NAME         AGE   SEX   Weight HOME Phone
===========
Matty Nigan  65     M    XX      XX    XX
..........
..........
..........
..........

나는 이 코드를 시도했다:

#!/bin/bash
source=path to the folder where the entries files are.
for i in $(cat file.txt); do # file.txt is including all the delimited text files names

 awk '
 /Name:/ {name=$2}
 /Age:/ {age=$2 }
 /Sex:/ {sex=$2}
 /Home: / {home=$3}
 /Phone:/ {phone=$3}
 BEGIN { FS=":"; print "name\t\tage\t\tsex\t\thome\t\tphone:\n---------"; }       
 {print $2,"\t\t",$3,"\t\t",$4,"\t\t",$6,"\t\t",$7;}END{ print "---------\nFile Complete" }'
' ${source}/${i}| sh > outdata.csv
done

불행히도 이것은 작동하지 않습니다! 내가 뭘 잘못했는지 모르겠습니다. 어떤 도움이라도 대단히 감사하겠습니다.

답변1

awk '
BEGIN {
    fmt="%-15s%-10s%-10s%-10s%-10s%-10s\n"
    printf fmt,"Name","Age","Sex","Weight","Home","Phone"
    print "---------"
}

{
    v=$0
    sub(/[^:]*: /, "", v)
    a[$1]=v
}

/Phone/ {
    printf fmt,a["NAME:"],a["Age:"],a["Sex:"],a["Weight:"],a["Home"],a["Phone"]
    delete a
}

END{ 
    print "---------\nFile Complete" 
}' file*

열 사이에 이중 탭을 사용하는 것은 문제가 있습니다. 예를 들어 긴 이름과 짧은 이름이 모두 있는 경우 열이 뒤섞여 정확히 잘못된 위치에 표시될 수 있습니다. 위에서는 주어진 너비로 열의 형식을 지정했습니다. 최상의 결과를 얻으려면 너비를 조정해야 할 수도 있습니다.

이로 인해 FS=":"문제가 발생할 수도 있습니다. 필드에는 계산에 혼란을 주는 콜론이 포함될 수 있습니다. 이는 다음과 같이 첫 번째 콜론의 정보를 삭제하여 방지할 수 있습니다. 다음 명령문은 모든 파일 정보를 배열로 캡처합니다 a.

v=$0
sub(/[^:]*: /, "", v)
a[$1]=v

첫 번째 필드가 키입니다. 첫 번째 콜론 공백 이후의 모든 내용은 값입니다.

단일 awk 명령으로 여러 파일을 처리할 수 있습니다. 위에서 언급한 대로 file*glob과 일치하는 모든 파일이 처리됩니다. 데이터 파일과 일치하는 모든 glob으로 바꾸십시오.

한 번에 한 사람씩 처리하십시오. 이는 코드가 많은 메모리를 필요로 하지 않으므로 대규모 데이터 세트에 적합하다는 것을 의미합니다.

샘플 출력

$ bash script.sh
Name           Age       Sex       Weight    Home      Phone     
---------
Matty Nigan    65        M         XX        XXXXX     XXX XXX XXXX
---------
File Complete

답변2

다음과 같이 구성된 awk를 사용해 보세요. 세부 정보가 포함된 배열을 만들고 마지막에 배치를 인쇄합니다.

awk -F: '
/^NAME/{name[c]=$2}
/^Age:/{age[c]=$2}
/^Sex:/{sex[c]=$2}
/^Weight:/{weight[c]=$2}
/^Home address:/{home[c]=$2}
/^Phone number:/{phone[c]=$2;c++}
END {
 print "NAME         AGE   SEX   Weight HOME Phone"
 print "==========="
 for(x in name) {
  printf "%-10s %3d    %s      %s %s %s\n",
    substr(name[x],2),
    age[x],
    sex[x],
    weight[x],
    home[x],
    phone[x]
 }
}'

답변3

또한 각 입력 레코드에 대해 "{print $2..."로 시작하는 문이 실행되는 것처럼 보입니다. /PHONE:/ 선택기 뒤에 인쇄 내용을 중괄호로 묶는 것이 좋습니다. 또한 이 작업을 수행하려면 BEGIN 섹션을 그대로 추가하는 대신 프로그램 헤드에 배치합니다.

이전 의견에서 지적했듯이 인쇄물에는 $2, $3, $4 등이 아닌 이름, 나이, 성별 등이 있어야 합니다.

/PHONE:/ {phone=$3}이(가) 문제를 일으킬 것 같아요. 샘플 데이터에 표시된 대로 전화번호의 세 자리 숫자 세트(공백으로 구분)는 awk에 $3 $4 $5로 나타납니다. 따라서 전화번호 전체를 수집하려면 /PHONE:/{phone = $3 "-" $4 "-" $5} 가 더 적합할 것입니다.

관련 정보