텍스트 파일의 열을 재정렬하는 방법은 무엇입니까?

텍스트 파일의 열을 재정렬하는 방법은 무엇입니까?
Month   Name  Marks  
2016-10 Sam   58  
2016-09 Sam   77  
2016-10 John  64  
2016-09 John  47  
2016-10 Mark  71  
2016-09 Mark  38  
2016-10 Steve 83  
2016-09 Steve 39  

나는 첫 번째 열에 월이 있고 두 번째 열에 각 학생의 점수가 있는 데이터베이스에서 이 데이터를 가져오고 있습니다. 이제 첫 번째 열에 이름이 있고 두 번째 열에 2016-10 태그가 있고 세 번째 열에 2016-09 태그가 있도록 편집하고 싶습니다.

답변1

입력 데이터가 "grades"라는 파일에 있다고 가정하고 다음을 시도해 보십시오.

$ awk 'BEGIN{ PROCINFO["sorted_in"]="@ind_str_desc"} NR==1{next} {m[$1]; n[$2]; g[$2,$1]=$3} END{for (name in n) {printf "%s",name; for (month in m) printf " %s",g[name,month]; print""}}' grades | column -t
Steve  83  39
Sam    58  77
Mark   71  38
John   64  47

출력은 학생당 한 행이며 성적은 월별로 내림차순으로 정렬됩니다.

코드를 여러 줄에 걸쳐 분산시키려는 경우:

gawk '
    BEGIN{ PROCINFO["sorted_in"]="@ind_str_desc"}
    NR==1{
        next
    }

    {
        m[$1]
        n[$2]
        g[$2,$1]=$3
    }

    END{
        for (name in n) {
            printf "%s",name
            for (month in m)
                printf " %s", g[name,month]
                print""
        }
    }

    ' grades | column -t

어떻게 작동하나요?

  • BEGIN{ PROCINFO["sorted_in"]="@ind_str_desc"}

    이는 배열이 인덱스별로 정렬되기를 원한다는 것을 awk에 알려줍니다. 이것이 GNU의 특징입니다.

  • NR==1{next}

    이는 awk에게 첫 번째 줄을 건너뛰도록 지시합니다. 출력 파일에 헤더를 추가하려면 여기서 할 수 있습니다.

  • m[$1]

    이는 awk에게 연관 배열에 현재 달에 대한 항목을 추가하도록 지시합니다 m. 입력에 어떤 달이 있는지 추적하는 데만 사용하므로 값을 할당할 필요가 없습니다.

  • n[$2]

    이는 연관 배열에 학생 이름에 대한 항목을 추가하도록 awk에 지시합니다 n. 입력에 어떤 달이 있는지 추적하는 데만 사용하므로 값을 할당할 필요가 없습니다.

  • g[$2,$1]=$3

    그러면 연관 배열의 학생 이름, 월 키 아래 값으로 성적이 할당됩니다 g.

  • END{for (name in n) {printf "%s",name; for (month in m) printf " %s",g[name,month]; print""}}

    파일 끝에 도달하면 각 학생의 모든 이름과 성적을 인쇄합니다.

  • column -t

    이 선택적 단계는 출력을 예쁘게 만듭니다.

답변2

격월로 필요하신 경우

sed '
    2~2{                                               #for even lines
        N                                              #attach next line
        s/\(\S\+ \)\(\S\+ \)[0-9]*\n\(\S\+\).*/\2\1\3/ #rearrange two line
    }
    1c\Name Month1 Month2                              #output new header
    ' file.data

아니면 이중 잣대

sed '
    1!N             #from second line attach next line 
    s/\S\+ //       #remove first field (2016-10)
    s/\n.* / /      #remove 2 fields in attached line
    t               #ommit 1st line
    s/$/1 Marks2/   #arrange header
    ' file.data

다른 버전

echo 'Name Marks1 Marks2' ;\
paste -sd' \n' <(tail -n +2 file.data) |
cut -d' ' -f 2,3,6

답변3

다소 조잡한 예:

여기서 변수를 m포함하려는 날짜와 해당 순서를 쉼표로 구분된 문자열로 설정합니다. 아래 예를 기반으로 하면 다음과 같습니다.

m=2016-10,2016-09

이는 다음을 제공합니다.

Name 2016-10 2016-09

이를 위해서는 이름이 고유해야 하며 공백이 없어야 합니다.

awk -v m=2016-10,2016-09 '
    NR==1{next}
    {
        # Set array x[name][month]=marks
        x[$2][$1]=$3
    }
    END {
        split(m, k, ",")
        printf "Name"
        for (v in k)
            printf "\t%s", k[v]
        for (e in x) {
            printf "\n%s", e
            for (v in k)
                printf "\t%s", x[e][k[v]]
        }
        print ""
    }
' data

예제 출력:

Name    2016-10 2016-09
Steve   83  39
Mark    71  38
John    64  47
Sam 58  77

통과 column -t:

Name   2016-10  2016-09
Steve  83       39
Mark   71       38
John   64       47
Sam    58       77

이것이 일회성이고 데이터가 예(주문, 2개월만 주문 등)를 따르는 경우에도 작동합니다.

awk 'NR==1{next}NR%2{print $3;next}{printf "%s\t%s\t",$2,$3}' data

관련 정보