Cat tập tin đến thiết bị đầu cuối ở tốc độ cụ thể của dòng mỗi giây


15

Tôi lười biếng và tôi có thể viết một kịch bản để làm điều này, nhưng tôi thậm chí còn quá lười biếng để nghĩ cách làm nó.

Tôi thường làm những việc như:

cris$ python runexperiment.py > output.txt
cris$ cat output.txt

Đôi khi, khi nhìn vào đầu ra dài của một thử nghiệm, tôi muốn cho trang chỉ cuộn và xem các mẫu liên tiếp hình thành và phân tán. Nhưng sử dụng con mèo trên một tập tin với 1 triệu dòng kết thúc trong khoảng 5 giây. Điều này là quá nhanh ngay cả đối với tôi.

Có cách nào để tôi có thể làm chậm tốc độ xem tệp, giống như 'tiện ích cuộn' không? Tôi muốn nhanh, nhưng không phải 200 nghìn dòng một giây (tất cả trong số đó có lẽ là màn hình thậm chí sẽ không bao giờ đăng ký).

Cái gì đó như

cris$ scroll -lps=300 output.txt

Và sau đó ngồi lại và xem 300 dòng mỗi giây trôi qua sẽ là lý tưởng, tôi tưởng tượng.


7
Hãy thử một cái gì đó như cat FILENAME | pv -l -L 900 -q. Giới hạn tính bằng byte trên giây, không phải dòng trên giây, vì vậy tôi đưa ra nhận xét này không phải là câu trả lời.
David Schwartz

Ok, đó là một tiện ích tuyệt vời, và nó hoạt động một phần. Nhưng vâng, nó là một chút choppy vì nó đi sau bps không lps.
Cris Stringfellow

Câu trả lời:


17

Ngắn gọn và dễ đọc :

perl -pe "system 'sleep .003'" log.txt

Tôi đăng giải pháp này vì chúng nhỏ và dễ đọc, vì nhận xét về câu trả lời của DMas dường như thúc đẩy loại giải pháp này!

Nhưng tôi ghét điều này bởi vì: Đối với lần chạy này, perl sẽ rẽ nhánh tới /bin/sleep300x / giây!

Đây là một người tiêu dùng ressource lớn! Cũng là một giải pháp tốt sai !!

Sử dụng giấc ngủ dựng sẵn trong

Thật không may, nội dung sleepđược giới hạn trong số nguyên. Vì vậy, chúng ta phải sử dụng selectthay thế:

perl -e 'print && select undef,undef,undef,.00333 while <>;'

Theo perl, print while <>có thể được thay thế bằng công -ptắc:

perl -pe 'select undef,undef,undef,.00333'

Hãy thử:

time /bin/ls -l /usr/bin | perl -pe 'select undef,undef,undef,.00333' | wc
   2667   24902  171131

real    0m9.173s
user    0m0.056s
sys     0m0.048s

bc -l < <(echo 2667/9.173)
290.74457647443584432573

Giải trình:

  • 300 dòng / giây có nghĩa là 1 dòng bằng 0,0033333333 giây.

  • printkhông có đối số in $_đó là không gian đầu vào mặc định .

  • gọi là ... | perl -e, ... | perl -nehoặc ... | perl -pe, đầu vào tiêu chuẩn sẽ được automaticaly giao cho *STDINđó là mô tả tập tin mặc định , vì vậy <>sẽ làm tương tự như <STDIN>đó sẽ đọc từ đầu vào tiêu chuẩn cho đến khi $/( tách hồ sơ đầu vào mà là theo mặc định một newline ) sẽ đạt được. Trong tiếng Anh, theo mặc định <>sẽ đọc một dòng từ đầu vào tiêu chuẩn và gán nội dung cho $_biến.

  • &&là một điều kiện, nhưng được sử dụng ở đó như một dấu tách lệnh chuỗi để sau khi (thành công) in một dòng, thực hiện lệnh tiếp theo.

  • selectlà một mẹo của lập trình viên để không sử dụngsleep . Lệnh này được thiết kế để bẫy các sự kiện trên các mô tả tệp (đầu vào và / hoặc đầu ra, tệp, ổ cắm và / hoặc ổ cắm mạng). Với lệnh này, một chương trình có thể đợi 3 loại sự kiện, nguồn cấp dữ liệu sẵn sàng để đọc , nguồn cấp dữ liệu sẵn sàng để viếtmột số sự kiện đã xảy ra trên nguồn cấp dữ liệu . Đối số thứ tư là thời gian chờ tính bằng giây, vì vậy cú pháp là select <feeds where wait for input>, <feeds where having to write>, <feed where something could happen>, <timeout>.

Để chính xác hơn, bạn có thể sử dụng Time::Hiresmô-đun perl:

perl -MTime::HiRes -pe 'BEGIN{$start=Time::HiRes::time;$sleepPerLine=1/300};select undef,undef,undef,($start + $sleepPerLine*$. - Time::HiRes::time)'

Lưu ý: $.số dòng đầu vào hiện tại .

Viết tốt hơn là cat >catLps.pl

#!/usr/bin/perl -w

use strict;
use Time::HiRes qw|time|;

my $start=time;
my $lps=300;

$lps=shift @ARGV if @ARGV && $ARGV[0]=~/^(\d+)$/;
my $sleepPerLine=1/$lps;

print &&
    select undef,undef,undef,($start + $sleepPerLine*$. - Time::HiRes::time)
    while <>

Sử dụng:

catLps.pl [lps] [file] [file]...

Đối số đầu tiên lpslà dòng tùy chọn trên mỗi giây đối số số (mặc định: 300)

Lưu ý: nếu tên tệp chỉ là số, bạn có thể phải chỉ định chúng bằng đường dẫn : ./3.

Giống như catđiều này có thể vượt qua các tệp được đưa ra làm đối số và / hoặc đầu vào tiêu chuẩn

Vì vậy, chúng tôi có thể:

TIMEFORMAT='%R' 
time seq 1 100 | ./catLps.pl 100 >/dev/null 
1.040

time seq 1 10000 | ./catLps.pl 10000 >/dev/null  
1.042

Cho vui:

export TIMEFORMAT='%R' ;clear ;time seq 1 $((LINES-2)) | ./catLps.pl $((LINES-2))

2
có vẻ như một số voodoo nghiêm trọng bạn đang làm ở đó. thật tuyệt, tôi đã thử nó và nó hoạt động. Tôi không biết làm thế nào bạn làm điều đó mặc dù. Perl chọn cái quái gì vậy? không? tôi có thể tìm nó kinh ngạc.
Cris Stringfellow

2
@CrisStringfellow Ok, tôi đã thêm một số giải thích và tập lệnh đầy đủ sử dụng Time::HiResmô-đun perl để chính xác hơn
F. Hauri

Chúa tôi. Đó là một câu trả lời tuyệt vời. Cảm ơn bạn. Tôi đã cố gắng nâng cấp nó lần thứ hai. Tôi đang học được điều gì đó bằng cách đọc lời giải thích tuyệt vời của bạn.
Cris Stringfellow

2
Bạn cũng có thể nêu ý kiến ​​của tôi ;-)
F. Hauri

@CrisStringfellow Trả lời đã được chỉnh sửa: bằng cách sử dụng -plệnh chuyển sang lệnh perl, tập lệnh đã được làm sáng!
F. Hauri

11

Chỉ cần sử dụng awk với giấc ngủ:

awk '{print $0; system("sleep .1");}' log.txt

Điều này làm việc cho tôi và cho tình huống của tôi là lựa chọn tốt nhất thay vì các tùy chọn kịch bản ở trên. Không chắc chắn tại sao câu trả lời này được bỏ phiếu.
Công dân Kepler

2
Không giống như giải pháp perl, nó khá dễ đọc.
Gunslinger

1
@Gunlinger: Cú pháp system(*sleep .1")sẽ tạo ra 10 dĩa / giây! Điều này có thể được viết perl -pe 'system "sleep .1"' log.txt: Có thể đọc được, nhưng rất tốn kém (không thân thiện với hệ thống!)
F. Hauri

Tôi cũng thích câu trả lời dễ đọc này. Điều duy nhất là nó sẽ kích hoạt lệnh ngủ shell cho mỗi dòng nó xuất ra. Nhưng là một lớp lót hoàn hảo có thể đọc được tôi không quan tâm.
itafire

0

Tôi đến bữa tiệc muộn, nhưng tôi thấy đây sẽ là một bài tập học tập hữu ích để thử trong python, vì vậy tôi sẽ đưa ra những gì tôi có:

#!/usr/bin/env python3

import argparse
from time import sleep

parser = argparse.ArgumentParser(description='Echo a file slowly')
parser.add_argument('-i',
                    '--input-file',
                    type=argparse.FileType('r'),
                    default='-')
parser.add_argument('-d',
                    '--delay-in-ms',
                    type=int,
                    default='100')
args = parser.parse_args()

for line in args.input_file:
    print(line.rstrip())
    sleep(args.delay_in_ms/1000.0)

Nó chấp nhận đầu vào từ stdin hoặc như một đối số (-i) và theo mặc định ghi một dòng trên 1/10 của giây, nhưng điều đó có thể được thay đổi bằng một đối số khác (-d).


Cảm ơn. Tôi đã bắt đầu phát triển một cái gì đó tương tự như ý tưởng này trong Python khi tôi tình cờ gặp Q & Ad này. Tôi lưu ý rằng Python cũng hỗ trợ chọn docs.python.org/3/l Library / select.html theo cách tương tự như Perl như được sử dụng trong câu trả lời của F. Hauri.
ybull
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.