grep -n | sort | sed | cut
( export LC_ALL=C
grep -n '' | sort -t: -nmk1,1 ./L - |
sed /:/d\;n | cut -sd: -f2-
) <./F
그것은 모든 크기의 입력으로 꽤 빨리 작동합니다 (일부 시간 테스트가 아래에 포함되어 있음) . 방법에 대한 몇 가지 참고 사항 :
export LC_ALL=C
- 다음 작업의 요점은 전체 파일을 lineno의 파일
./F
과 인라인으로 쌓는 ./L
것이므로 ASCII [0-9]
문자와 :
콜론 만 걱정할 필요가 있습니다 .
- 따라서 UTF-8이 포함 된 경우보다 128 개 문자 집합에서 11 개의 문자를 찾는 것에 대해 걱정하는 것이 더 간단합니다.
grep -n ''
- 그러면
LINENO:
stdin-또는에서 모든 줄의 머리글에 문자열이 삽입됩니다 <./F
.
sort -t: -nmk1,1 ./L -
sort
무시 전혀 입력 파일을 정렬하고 대신합니다 (제대로) 가 미리 정렬되어 가정 및 -m
그들을 erges -numerically
기본적으로 가능한 모든 이외에는 아무 것도 무시하고, 정렬 된 순서 -k1,1
일 발생 -t:
어쨌든 콜론 문자를.
- 이것은 (일부 시퀀스가 얼마나 멀리 떨어져 있는지에 따라) 수행 할 임시 공간이 필요할 수 있지만 적절한 정렬과 비교할 때 많이 필요하지 않으며 백 트랙킹이 없기 때문에 매우 빠릅니다.
sort
./L
라인 번호가의 해당 라인 바로 앞에 오는 단일 스트림을 출력합니다 ./F
. ./L
줄이 항상 짧기 때문에 항상 줄이 먼저 나옵니다.
sed /:/d\;n
- 현재 행이
/:/
콜론 과 일치하면 d
출력에서 제외됩니다. 그렇지 않으면 현재 및 n
내선을 자동 인쇄합니다 .
- 그리고
sed
자두 sort
에의 출력 만을 콜론과 다음 줄을 일치하지 않는 연속 라인 쌍 - 또는에서 불과 라인에 ./L
다음 다음.
cut -sd: -f2-
cut
-s
elimiter -d:
문자열 중 하나 이상을 포함하지 않는 입력 행의 출력을 억제합니다. 따라서 ./L
행이 완전히 제거됩니다.
- 그런 줄에 대해서는 첫 번째
:
콜론으로 구분 된 -f
필드가 cut
사라지고 grep
삽입 된 모든 lineno 가 사라집니다 .
작은 입력 테스트
seq 5 | sed -ne'2,3!w /tmp/L
s/.*/a-z &\& 0-9/p' >/tmp/F
... 5 줄의 샘플 입력을 생성합니다. 그때...
( export LC_ALL=C; </tmp/F \
grep -n '' | sort -t: -nmk1,1 ./L - |
sed /:/d\;n | cut -sd: -f2-
)| head - /tmp[FL]
...인쇄물...
==> standard input <==
a-z 1& 0-9
a-z 4& 0-9
a-z 5& 0-9
==> /tmp/F <==
a-z 1& 0-9
a-z 2& 0-9
a-z 3& 0-9
a-z 4& 0-9
a-z 5& 0-9
==> /tmp/L <==
1
4
5
더 큰 시한 테스트
꽤 큰 파일 몇 개를 만들었습니다.
seq 5000000 | tee /tmp/F |
sort -R | head -n1500000 |
sort -n >/tmp/L
... /tmp/F
5mil 라인을 넣고 1.5mil을 임의로 선택한 라인에 넣습니다 /tmp/L
. 나는 그랬다.
time \
( export LC_ALL=C
grep -n '' | sort -t: -nmk1,1 ./L - |
sed /:/d\;n | cut -sd: -f2-
) <./F |wc - l
인쇄 :
1500000
grep -n '' \
0.82s user 0.05s system 73% cpu 1.185 total
sort -t: -nmk1,1 /tmp/L - \
0.92s user 0.11s system 86% cpu 1.185 total
sed /:/d\;n \
1.02s user 0.14s system 98% cpu 1.185 total
cut -sd: -f2- \
0.79s user 0.17s system 80% cpu 1.184 total
wc -l \
0.05s user 0.07s system 10% cpu 1.183 total
(백 슬래시를 추가했습니다)
현재 여기에 제공되는 솔루션 중에서 이것은 가장 빠르지 만 내 컴퓨터에서 위에서 생성 된 데이터 세트에 대해 피트했을 때 하나입니다. 다른 사람들 중 단 한 사람 만이 2 위를 차지하기 시작 perl
했습니다 .
이것은 원래 제공된 솔루션이 결코 아닙니다. 다른 사람들이 제공하는 조언 / 영감 덕분에 실행 시간의 3 분의 1이 줄었습니다. 더 느린 솔루션에 대해서는 포스트 히스토리를 참조하십시오 (그러나 그 이유는 무엇입니까?) .
또한 내 시스템의 다중 CPU 아키텍처가 아니고 해당 파이프 라인의 각 프로세스를 동시에 실행하지 않으면 다른 답변이 훨씬 더 잘 경쟁 할 수 있습니다. 이들은 모두 동시에 자체 프로세서 코어에서 데이터를 전달하고 전체의 작은 부분을 수행하면서 동시에 작동합니다. 꽤 멋지다.
그러나 가장 빠른 해결책은 ...
그러나 가장 빠른 솔루션은 아닙니다. 여기서 제공되는 가장 빠른 솔루션은 C 프로그램 입니다. 나는 그것을 불렀다 cselect
. X 클립 보드에 복사 한 후 다음과 같이 컴파일했습니다.
xsel -bo | cc -xc - -o cselect
나는 그랬다.
time \
./cselect /tmp/L /tmp/F |
wc -l
... 결과는 ...
1500000
./cselect /tmp/L /tmp/F \
0.50s user 0.05s system 99% cpu 0.551 total
wc -l \
0.05s user 0.05s system 19% cpu 0.551 total