Lệnh đó phụ thuộc vào trình bao tạo 5000 đối số và chuyển chúng tới printf
đó bỏ qua chúng. Mặc dù nó có vẻ khá nhanh - và có liên quan đến một số thứ - shell vẫn phải tạo ra tất cả các chuỗi đó dưới dạng đối số (và phân định chúng) , v.v.
Bên cạnh thực tế là các Hs được tạo không thể được in cho đến khi trình bao đầu tiên lặp lại thành 5000, lệnh đó cũng tiêu tốn trong bộ nhớ tất cả những gì nó cần để lưu trữ và phân định các đối số chuỗi số để printf
cộng với Hs. Chỉ đơn giản là bạn có thể làm:
printf %05000s|tr \ H
... tạo ra một chuỗi 5000 khoảng trắng - mà, ít nhất, thường chỉ là một byte cho mỗi và không có gì để phân định vì chúng không được phân định. Một vài thử nghiệm chỉ ra rằng thậm chí chỉ với 5000 byte, chi phí của ngã ba và đường ống cần thiết tr
là đáng giá ngay cả trong trường hợp này, và hầu như luôn luôn là khi con số tăng cao hơn.
Tôi đã chạy ...
time bash -c 'printf H%.0s {1..5000}' >/dev/null
... và ...
time bash -c 'printf %05000s|tr \ H' >/dev/null
Mỗi lần khoảng 5 lần một mảnh (không có gì khoa học ở đây - chỉ là giai thoại) và phiên bản mở rộng niềng trung bình hơn 0,02 giây trong tổng thời gian xử lý, nhưng phiên bản trung bình đạt tr
khoảng 0,012 giây - và tr
phiên bản đã đánh bại nó mỗi lần. Tôi không thể nói rằng tôi ngạc nhiên - {brace expansion}
là một tính năng tốc ký tương tác hữu ích, nhưng thường là một điều khá lãng phí khi làm bất kỳ loại kịch bản nào có liên quan. Hình thức phổ biến:
for i in {[num]..[num]}; do ...
... Khi bạn nghĩ về nó, thực sự là hai for
vòng lặp - đầu tiên là bên trong và ngụ ý rằng shell phải lặp theo một cách nào đó để tạo ra các vòng lặp đó trước khi lưu tất cả chúng và lặp lại chúng cho for
vòng lặp của bạn . Những việc như vậy thường được thực hiện tốt hơn như:
iterator=$start
until [ "$((iterator+=interval))" -gt "$end" ]; do ...
... bởi vì bạn chỉ lưu trữ một vài giá trị và ghi đè lên chúng khi bạn thực hiện cũng như thực hiện phép lặp trong khi bạn tạo các lần lặp.
Dù sao, giống như phần đệm không gian được đề cập trước đó, bạn cũng có thể sử dụng printf
để zeropad một số chữ số tùy ý, tất nhiên, như:
printf %05000d
Tôi làm cả hai mà không có đối số bởi vì đối với mọi đối số được chỉ định trong printf
chuỗi định dạng của khi không tìm thấy đối số, chuỗi null được sử dụng - được hiểu là số không cho đối số chữ số hoặc chuỗi trống cho chuỗi.
Đây là mặt khác (và - theo ý kiến của tôi - hiệu quả hơn) của đồng xu khi so sánh với lệnh trong câu hỏi - trong khi có thể không nhận được gì từ một thứ gì đó như bạn làm khi bạn printf %.0
kéo dài chuỗi cho mỗi đối số, do đó, cũng vậy nó có thể nhận được một cái gì đó từ không có gì.
Vẫn nhanh hơn cho số lượng lớn byte được tạo mà bạn có thể sử dụng dd
như:
printf \\0| dd bs=64k conv=sync
... và đối số dd
của các tệp thông thường seek=[num]
có thể được sử dụng để tạo lợi thế lớn hơn. Bạn có thể nhận 64k dòng mới chứ không phải là null nếu bạn thêm ,unblock cbs=1
vào bên trên và từ đó có thể tiêm chuỗi tùy ý mỗi dòng với paste
và /dev/null
- nhưng trong trường hợp đó, nếu nó có sẵn cho bạn, bạn cũng có thể sử dụng:
yes 'output string forever'
Dưới đây là một số dd
ví dụ nữa:
dd bs=5000 seek=1 if=/dev/null of=./H.txt
... tạo ra (hoặc cắt bớt) một \0NUL
tệp được điền trong thư mục hiện tại có tên H.txt có kích thước 5000 byte. dd
tìm kiếm thẳng đến phần bù và NUL-lấp đầy tất cả đằng sau nó.
<&1 dd bs=5000 conv=sync,noerror count=1 | tr \\0 H >./H.txt
... tạo ra một tệp có cùng tên và kích thước nhưng được điền vào ký tự w / H. Nó lợi dụng dd
hành vi cụ thể của việc viết ra ít nhất một khối null hoàn toàn trong trường hợp xảy ra lỗi đọc noerror
và sync
chuyển đổi được chỉ định (và - không count=
- có thể sẽ kéo dài hơn bạn muốn) và chuyển hướng có chủ ý một mô tả tập tin writeonly tại dd
stdin.
tcsh
hoặczsh
,repeat 5000 printf H
dễ hiểu hơn. Vớiperl
:print "H" x 5000
(lưu ý rằng{1..5000}
là một nhà điều hành zsh lấy cảm hứng từperl
's1..5000
một và sau đó sao chép bởi ksh93 và bash)