grep -n | sort | sed | cut
( export LC_ALL=C
grep -n '' | sort -t: -nmk1,1 ./L - |
sed /:/d\;n | cut -sd: -f2-
) <./F
Điều đó sẽ hoạt động khá nhanh (một số bài kiểm tra thời gian được bao gồm bên dưới) với đầu vào có kích thước bất kỳ. Một số lưu ý về cách:
export LC_ALL=C
- Bởi vì mục đích của thao tác sau là lấy toàn bộ tệp
./F
xếp chồng lên nhau với ./L
tệp lineno của nó, các ký tự duy nhất chúng ta thực sự cần phải lo lắng là các [0-9]
chữ số ASCII và :
dấu hai chấm.
- Vì lý do đó, việc lo lắng về việc tìm kiếm 11 ký tự đó trong một bộ 128 sở hữu sẽ đơn giản hơn so với nếu UTF-8 có liên quan.
grep -n ''
- Điều này chèn chuỗi
LINENO:
vào đầu của mỗi dòng trong stdin - hoặc <./F
.
sort -t: -nmk1,1 ./L -
sort
bỏ qua việc sắp xếp các tập tin đầu vào của nó, và thay vào đó (chính xác) cho rằng chúng được sắp đặt trước và sắp xếp -m
chúng -numerically
theo thứ tự được sắp xếp, về cơ bản bỏ qua mọi thứ ngoài bất kỳ ký tự đại tràng nào có thể -k1,1
xảy ra -t:
.
- Mặc dù điều này có thể yêu cầu một số không gian tạm thời để thực hiện (tùy thuộc vào việc một số trình tự có thể xảy ra cách nhau bao xa) , nhưng nó sẽ không đòi hỏi nhiều so với một loại thích hợp, và nó sẽ rất nhanh vì nó liên quan đến việc quay lui bằng không.
sort
sẽ tạo ra một luồng đơn trong đó bất kỳ dòng lineno nào ./L
sẽ ngay lập tức đi trước các dòng tương ứng ./F
. ./L
Các dòng luôn luôn đến đầu tiên vì chúng ngắn hơn.
sed /:/d\;n
- Nếu dòng hiện tại khớp với
/:/
dấu hai chấm d
từ đầu ra. Khác, tự động in dòng hiện tại và n
ext.
- Và do đó , đầu ra của
sed
prunes chỉ cho các cặp dòng liên tiếp không khớp với dấu hai chấm và dòng sau - hoặc, chỉ một dòng từ và sau đó đến dòng tiếp theo.sort
./L
cut -sd: -f2-
cut
-s
nhấn mạnh từ đầu ra của những dòng đầu vào không chứa ít nhất một trong các -d:
chuỗi loại bỏ của nó - và vì vậy ./L
các dòng của nó được cắt tỉa hoàn toàn.
- Đối với những dòng này, ield
:
được phân định bằng dấu hai chấm đầu tiên của chúng -f
sẽ cut
biến mất - và tất cả các grep
lineno được chèn vào.
kiểm tra đầu vào nhỏ
seq 5 | sed -ne'2,3!w /tmp/L
s/.*/a-z &\& 0-9/p' >/tmp/F
... tạo ra 5 dòng đầu vào mẫu. Sau đó...
( export LC_ALL=C; </tmp/F \
grep -n '' | sort -t: -nmk1,1 ./L - |
sed /:/d\;n | cut -sd: -f2-
)| head - /tmp[FL]
... bản in ...
==> 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
kiểm tra thời gian lớn hơn
Tôi đã tạo ra một vài tệp khá lớn:
seq 5000000 | tee /tmp/F |
sort -R | head -n1500000 |
sort -n >/tmp/L
... trong đó đặt 5 triệu dòng /tmp/F
và 1,5 triệu dòng được chọn ngẫu nhiên vào đó /tmp/L
. Sau đó tôi đã làm:
time \
( export LC_ALL=C
grep -n '' | sort -t: -nmk1,1 ./L - |
sed /:/d\;n | cut -sd: -f2-
) <./F |wc - l
Nó được in:
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
(Tôi đã thêm dấu gạch chéo ngược ở đó)
Trong số các giải pháp hiện đang được cung cấp ở đây, đây là giải pháp nhanh nhất trong số chúng nhưng một giải pháp khi đọ sức với bộ dữ liệu được tạo ở trên trên máy của tôi. Trong số những người khác chỉ có một người đến gần để tranh giành vị trí thứ hai, và đó là meuh perl
ở đây .
Đây không phải là giải pháp ban đầu được đưa ra - nó đã giảm một phần ba thời gian thực hiện nhờ lời khuyên / cảm hứng được cung cấp bởi người khác. Xem lịch sử bài viết cho các giải pháp chậm hơn (nhưng tại sao?) .
Ngoài ra, điều đáng chú ý là một số câu trả lời khác rất có thể tranh luận tốt hơn nếu không phải là kiến trúc đa cpu của hệ thống của tôi và việc thực hiện đồng thời từng quy trình trong đường ống đó. Tất cả đều hoạt động cùng một lúc - mỗi lõi trên bộ xử lý riêng - truyền xung quanh dữ liệu và thực hiện phần nhỏ của chúng. Nó thật tuyệt
nhưng giải pháp nhanh nhất là ...
Nhưng nó không phải là giải pháp nhanh nhất. Giải pháp nhanh nhất được cung cấp ở đây, bàn tay xuống, là chương trình C . Tôi gọi nó cselect
. Sau khi sao chép nó vào clipboard X của tôi, tôi đã biên dịch nó như sau:
xsel -bo | cc -xc - -o cselect
Sau đó tôi đã làm:
time \
./cselect /tmp/L /tmp/F |
wc -l
... và kết quả 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