Tôi không chắc điều này tốt hơn việc thực hiện nó trong bộ nhớ, nhưng với sed
điều đó dẫn đến r
sự bất ổn của nó cho mọi dòng trong infile của nó và một dòng khác ở phía bên kia của một đường ống xen kẽ H
không gian cũ với các dòng đầu vào ...
cat <<\IN >/tmp/tmp
Row1,10
Row2,20
Row3,30
Row4,40
IN
</tmp/tmp sed -e 'i\
' -e 'r /tmp/tmp' |
sed -n '/./!n;h;N;/\n$/D;G;s/\n/ /;P;D'
ĐẦU RA
Row1,10 Row1,10
Row1,10 Row2,20
Row1,10 Row3,30
Row1,10 Row4,40
Row2,20 Row1,10
Row2,20 Row2,20
Row2,20 Row3,30
Row2,20 Row4,40
Row3,30 Row1,10
Row3,30 Row2,20
Row3,30 Row3,30
Row3,30 Row4,40
Row4,40 Row1,10
Row4,40 Row2,20
Row4,40 Row3,30
Row4,40 Row4,40
Tôi đã làm điều này theo cách khác. Nó lưu trữ một số trong bộ nhớ - nó lưu trữ một chuỗi như:
"$1" -
... cho mỗi dòng trong tệp.
pairs(){ [ -e "$1" ] || return
set -- "$1" "$(IFS=0 n=
case "${0%sh*}" in (ya|*s) n=-1;; (mk|po) n=+1;;esac
printf '"$1" - %s' $(printf "%.$(($(wc -l <"$1")$n))d" 0))"
eval "cat -- $2 </dev/null | paste -d ' \n' -- $2"
}
Nó rất nhanh. Đó cat
là tệp nhiều lần như có các dòng trong tệp tới a |pipe
. Ở phía bên kia của đường ống mà đầu vào được hợp nhất với chính tệp đó nhiều lần như có các dòng trong tệp.
Các case
công cụ chỉ dành cho tính di động - yash
và zsh
cả hai thêm một yếu tố để phân chia, trong khi mksh
và posh
cả hai đều mất một. ksh
, dash
, busybox
, Và bash
tất cả chia ra chính xác như nhiều lĩnh vực như có zero như in bằng printf
. Như đã viết ở trên, kết quả tương tự cho mỗi một trong các shell được đề cập ở trên trên máy của tôi.
Nếu tệp quá dài, có thể có $ARGMAX
vấn đề với quá nhiều đối số trong trường hợp bạn cần giới thiệu xargs
hoặc tương tự.
Cho cùng một đầu vào tôi đã sử dụng trước khi đầu ra giống hệt nhau. Nhưng, nếu tôi định đi lớn hơn ...
seq 10 10 10000 | nl -s, >/tmp/tmp
Điều đó tạo ra một tệp gần giống với những gì tôi đã sử dụng trước đây (sans 'Row') - nhưng ở 1000 dòng. Bạn có thể tự mình thấy nó nhanh như thế nào:
time pairs /tmp/tmp |wc -l
1000000
pairs /tmp/tmp 0.20s user 0.07s system 110% cpu 0.239 total
wc -l 0.05s user 0.03s system 32% cpu 0.238 total
Tại 1000 dòng có một số thay đổi nhỏ về hiệu suất giữa các shell - bash
luôn là chậm nhất - nhưng vì công việc duy nhất họ làm dù sao là tạo ra chuỗi arg (1000 bản sao filename -
) nên hiệu quả là tối thiểu. Sự khác biệt về hiệu suất giữa zsh
- như trên - và bash
là 100 giây trong đây.
Đây là một phiên bản khác nên hoạt động cho một tệp có độ dài bất kỳ:
pairs2()( [ -e "$1" ] || exit
rpt() until [ "$((n+=1))" -gt "$1" ]
do printf %s\\n "$2"
done
[ -n "${1##*/*}" ] || cd -P -- "${1%/*}" || exit
: & set -- "$1" "/tmp/pairs$!.ln" "$(wc -l <"$1")"
ln -s "$PWD/${1##*/}" "$2" || exit
n=0 rpt "$3" "$2" | xargs cat | { exec 3<&0
n=0 rpt "$3" p | sed -nf - "$2" | paste - /dev/fd/3
}; rm "$2"
)
Nó tạo ra một liên kết mềm với đối số đầu tiên của nó /tmp
bằng một tên bán ngẫu nhiên để nó không bị treo trên các tên tệp lạ. Điều đó quan trọng bởi vì cat
các đối số được đưa đến nó qua một đường ống thông qua xargs
. cat
Đầu ra của được lưu vào <&3
trong khi sed
p
gợi ý mọi dòng trong đối số đầu tiên nhiều lần như có các dòng trong tệp đó - và tập lệnh của nó cũng được đưa đến nó thông qua một đường ống. Một lần nữa paste
hợp nhất đầu vào của nó, nhưng lần này chỉ cần hai đối số -
một lần nữa cho đầu vào tiêu chuẩn và tên liên kết /dev/fd/3
.
Cuối cùng - /dev/fd/[num]
liên kết - sẽ hoạt động trên bất kỳ hệ thống linux nào và nhiều hệ thống khác bên cạnh đó, nhưng nếu nó không tạo ra một ống có tên mkfifo
và sử dụng thay thế thì nó cũng hoạt động tốt.
Điều cuối cùng nó làm là rm
liên kết mềm mà nó tạo ra trước khi thoát.
Phiên bản này thực sự nhanh hơn vẫn còn trên hệ thống của tôi. Tôi đoán đó là bởi vì mặc dù nó thực thi nhiều ứng dụng hơn, nhưng nó bắt đầu xử lý chúng ngay lập tức - trong khi trước khi nó xếp chồng chúng lên trước.
time pairs2 /tmp/tmp | wc -l
1000000
pairs2 /tmp/tmp 0.30s user 0.09s system 178% cpu 0.218 total
wc -l 0.03s user 0.02s system 26% cpu 0.218 total