다음 형식의 파일에서 가져오는 명령을 찾고 있습니다.
hello 32
hello 67
hi 2
ho 1212
ho 1390
ho 3000
이 형식을 사용하면("그룹"의 마지막 행을 가져와 중복 제거):
hello 67
hi 2
ho 3000
현재 저는 Python과 pandas 스니펫을 사용하고 있습니다.
df = pd.read_csv(self.input().path, sep='\t', names=('id', 'val'))
# how to replace this logic with shell commands?
surface = df.drop_duplicates(cols=('id'), take_last=True)
with self.output().open('w') as output:
surface.to_csv(output, sep='\t', cols=('id', 'val'))
업데이트: 훌륭한 답변에 감사드립니다. 다음은 몇 가지 벤치마크입니다.
입력 파일 크기는 246M이고 8583313줄을 포함합니다. 순서는 중요하지 않습니다. 첫 번째 열의 크기는 9자로 고정되어 있습니다.
입력 파일 예:
000000027 20131017023259.0 00
000000027 20131017023259.0 11
000000035 20130827104320.0 01
000000035 20130827104320.0 04
000000043 20120127083412.0 01
...
time space complexity
tac .. | sort -k1,1 -u 27.43682s O(log(n))
Python/Pandas 11.76063s O(n)
awk '{c[$1]=$0;} END{for(... 11.72060s O(n)
첫 번째 열의 길이는 고정되어 있으므로 다음을 uniq -w
사용할 수도 있습니다.
tac {input} | uniq -w 9 3.25484s O(1)
답변1
이건 미친 것 같고 더 좋은 방법이 있었으면 좋겠지만 다음과 같습니다.
tac foo | sort -k 1,1 -u
tac
파일을 반전하여 첫 번째 파일 대신 마지막 파일을 가져오는 데 사용됩니다.
-k 1,1
비교를 위해 첫 번째 필드만 사용한다고 말합니다.
-u
독특하게 만드세요.
답변2
출력 순서가 마음에 들지 않으면 awk
해결 방법은 다음과 같습니다.
$ awk '
{a[$1] = !a[$1] ? $2 : a[$1] < $2 ? $2 : a[$1]}
END {
for (i in a) { print i,a[i] }
}
' file
hi 2
hello 67
ho 3000
답변3
추가 옵션:
perl
, 행 순서에 관심이 없는 경우.perl -lane '$k{$F[0]}=$F[1]; END{print "$_ $k{$_}" for keys(%k)}' file
더 간단하다
awk
awk '{c[$1]=$0;} END{for(i in c){print c[i]}}' file
멍청한 껍질
while read a b; do grep -w ^"$a" file | tail -n1 ; done < file | uniq