텍스트 파일의 정렬 키를 선택하는 데 문제가 있습니다.

텍스트 파일의 정렬 키를 선택하는 데 문제가 있습니다.

다음과 같은 텍스트 파일이 있다고 가정해 보겠습니다.

e8:b4:c8:b2:d8:b9                       "Biswas Gautam"                   2016            me            Mob
ec:8e:b5:f8:a2:12                       "Dipin Gyawali"                   2015            me            Lan
f0:27:65:70:91:62                       "Karan Rai"                       2016            cs            Mob
f0:de:f1:33:33:32                       "Dipendra L. Karki"               2015            me            Lan

내 항목(기계 공학) 및 cs(컴퓨터 과학)와 같은 배치를 세 번째 열(연도), 네 번째 열 및 이름별로 정렬하고 싶습니다.

그러나 두 번째 열 이름은 문제를 야기합니다. 때로는 중간 이름이 있어서 원래 솔루션과 충돌합니다. 그래서 큰 따옴표가 트릭을 수행할 것이라고 생각합니다. 하지만 큰따옴표 안의 공백을 무시하는 방법을 모르겠습니다.

sort -k 4 -k 5 -k 2 -kfilename

공백이 3개가 생기기 때문에 4개를 썼습니다. 하나는 열로 인해 하나는 전체 이름(이름[공백]성)으로 인해 발생합니다.

이런 식으로 정렬할 수 있는 방법이 있나요?

답변1

파일 형식이 표시된 대로 엄격하게 지정된 경우 sort특정 열을 키로 사용하도록 요구할 수 있습니다.

sort -k1.75,1.78n -k1.91,1.92 -k1.105,1.107 -k1.41,1.74 input

...샘플 입력을 다음으로 변환합니다.

f0:de:f1:33:33:32                       "Dipendra Karki"                  2015            me            Lan
ec:8e:b5:f8:a2:12                       "Dipin Gyawali"                   2015            me            Lan
f0:27:65:70:91:62                       "Karan Rai"                       2016            cs            Mob
e8:b4:c8:b2:d8:b9                       "Biswas Gautam"                   2016            me            Mob

답변2

$ sed -E 's/ {3,}/@/g' file | sort -t @ -k3,3 -k5,5 | sed 's/@/    /g'
ec:8e:b5:f8:a2:12    "Dipin Gyawali"    2015    me    Lan
f0:de:f1:33:33:32    "Dipendra Karki"    2015    me    Lan
e8:b4:c8:b2:d8:b9    "Biswas Gautam"    2016    me    Mob
f0:27:65:70:91:62    "Karan Rai"    2016    cs    Mob

이렇게 하면 3개 이상의 공백이 해당 문자로 대체됩니다 @(데이터에 없는 모든 문자가 작동함).

그런 다음 sort입력이 @분리된 필드로 해석되고 세 번째 필드(연도)와 다섯 번째 필드(장치)로 정렬되도록 지시합니다. 마지막으로 정렬된 데이터의 각 공백을 4개의 공백으로 바꿉니다 sed. 여기에 리터럴 탭을 삽입하거나 GNU를 사용할 수 있습니다.@\tsed

더 아름다운:

$ sed -E 's/ {3,}/@/g' file | sort -t @ -k3,3 -k5,5 | column -s @ -t
ec:8e:b5:f8:a2:12  "Dipin Gyawali"   2015  me  Lan
f0:de:f1:33:33:32  "Dipendra Karki"  2015  me  Lan
e8:b4:c8:b2:d8:b9  "Biswas Gautam"   2016  me  Mob
f0:27:65:70:91:62  "Karan Rai"       2016  cs  Mob

다음은 awk각 열을 왼쪽 맞춤, 20자 너비 문자열로 형식화하는 데 사용됩니다.

$ sed -E 's/ {3,}/@/g' file | sort -t @ -k3,3 -k5,5 | awk -F@ '{ for (i=1;i<=NF;++i) printf("%-20s",$i); print "" }'
ec:8e:b5:f8:a2:12   "Dipin Gyawali"     2015                me                  Lan
f0:de:f1:33:33:32   "Dipendra Karki"    2015                me                  Lan
e8:b4:c8:b2:d8:b9   "Biswas a Gautam"   2016                me                  Mob
f0:27:65:70:91:62   "Karan Rai"         2016                cs                  Mob

또는 개별적으로 형식을 지정할 수 있습니다.

$ sed -E 's/ {3,}/@/g' file | sort -t @ -k3,3 -k5,5 | awk -F@ '{ printf("%s %-30s %-30s %-30s %s\n", $1,$2,$3,$4,$5) }'
ec:8e:b5:f8:a2:12 "Dipin Gyawali"                2015                           me                             Lan
f0:de:f1:33:33:32 "Dipendra Karki"               2015                           me                             Lan
e8:b4:c8:b2:d8:b9 "Biswas a Gautam"              2016                           me                             Mob
f0:27:65:70:91:62 "Karan Rai"                    2016                           cs                             Mob

답변3

간격을 정확하게 유지하려면(형식을 다시 지정하는 대신,코살로난다의 답변) 정확한 열 위치에 의존하고 싶지 않습니다(예:제프 샬러의 답변), 다음과 같은 Perl 스크립트가 작동합니다.

#!/usr/bin/perl
use 5.022;

my @dat;
while (<<>>) {
    #          0     1      2        3     4     5     6     7     8
    #          mac   sp     name     sp    yr    sp    dpt   sp    net
    my @m = /^(\S+) (\s+) "([^"]+)" (\s+) (\S+) (\s+) (\S+) (\s+) (\S+)$/x
        or die "invalid line: $_";
    push @dat, \@m;
}

@dat = sort {
    $a->[4] <=> $b->[4] || $a->[6] cmp $b->[6] || $a->[2] cmp $b->[2]
} @dat;

foreach (@dat) {
    print join('', @$_), "\n";
}

Perl v5.22.0 이상을 <<>>연산자로 사용하십시오. 이를 사용하는 경우 이전 버전의 Perl에서도 작동해야 합니다 <>. 이 프로그램에는 기본적으로 세 개의 "문단"이 있습니다. 첫 번째 문단은 정규식을 사용하여 줄을 구문 분석하고 사용된 정확한 간격도 캡처합니다. 두 번째 단락에서는 데이터를 정렬합니다. 세 번째 단락에서는 이를 다시 인쇄합니다.

답변4

또 다른 방법은 각 공백 문자를 다음으로 바꾸는 것입니다.~ 사이자리 표시자 @로 따옴표를 묶은 다음 정렬하고 @ 문자를 다시 공백으로 변경합니다.

perl -pe 's#("[^"]*")#$1 =~ s/ /@/rg#eg' filename | sort -k 3 -k 4 -k 2 | sed 's/@/ /g'

관련 정보