다음과 같은 텍스트 파일이 있다고 가정해 보겠습니다.
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를 사용할 수 있습니다.@
\t
sed
더 아름다운:
$ 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'