2014-01-07 3 views
8

나는 그런 내가 실행할 때와 같은 쉘 명령 X를 찾고 있어요 :버퍼를 지연시키는 쉘 명령이 있습니까?

command_a | X 5000 | command_b 

command_astdout가 (적어도) 오초 후에 command_bstdin에 기록됩니다.

지연 버퍼의 일종.

는 지금까지 내가 아는 한,/mbufferbuffer은 일정 속도 (초당 바이트의 고정 된 수의)에서 쓸 수 있습니다. 대신, 나는 일정한 지연을 시간 (t = 0 때 X 읽을 때 command_a 출력 청크, t = 5000에서 command_b이이 청크 작성해야합니다)입니다 싶습니다.

[편집] 나는 그것을 구현 한이 같은 https://github.com/rom1v/delay

+0

이러한 필터 명령이 아닌 사소한하지만, 쓰기 상당히 솔직 할 것이다. 나는 그것을하는 기존의 도구에 대해 알지 못한다. –

+0

타이밍이 정확해야하고 입력의 최소 "청크"는 무엇입니까? 시간 0에 바이트 'A'를 입력하고 시간 0.7에 바이트 'B'를 넣었고 시간 1.9에 바이트 'C'를 입력하면 출력을 정확하게 타이밍해야합니까 (5.0, 5.7 및 6.9 초)? 또는 ABC가 7.0 초에 출력 될 수 있습니까? 버퍼의 최대 크기는 얼마입니까? 버퍼가 가득 차기 전에 얼마나 많은 Mb의 데이터가 지연되어야합니까? – grebneke

+0

이상적으로는 거의 정확하게 시간을 측정해야합니다 (예 : 100ms 이내, 4.9 ~ 5.1, 5.6 ~ 5.8, 6.8 ~ 7). 바이트 단위의 버퍼 크기는 다른 매개 변수 여야합니다 ('-d 5000 -s 2m'). – rom1v

답변

0

뭔가?

#!/bin/bash 
while : 
do 
    read line 
    sleep 5 
    echo $line 
done 

대해 무엇을 다음

chmod +x slowboy 

을 "slowboy"로 파일을 저장하고 난 당신이 쉘 명령 찾고있는 것을 알고

command_a | ./slowboy | command_b 
+0

당신은 shebang을 잊어 버렸습니다. – glglgl

+0

감사합니다. 추가 문자 :-) –

+1

각 줄마다 5 초가 지연됩니다. command_a가 5 초마다 1보다 빠른 행을 출력하면 지연 시간이 길어지고 길어집니다. –

7

으로 실행하지만, 당신의 이익을 위해 서브 셸을 사용합니까? 뭔가 같은 : grep에 따라서

command_a | (sleep 5; command_b) 

파일을 통해 cat -ed (내가, 내가 알고, cat의 잘못된 사용을 알고 있지만 그냥 예) :

cat filename | (sleep 5; grep pattern) 

더 완벽한 예 :

$ cat testfile 
The 
quick 
brown 
fox 
$ cat testfile | (sleep 5; grep brown) 
# A 5-second sleep occurs here 
brown 

Michale Kropat이 권장하는 것처럼 심지어 sleep 인 그룹 명령도 작동합니다 (틀림없이 더 정확할 것입니다). 그래서 같이 :

$ cat testfile | { sleep 5; grep brown; } 

참고 :이 필요하므로, (여기 grep brown)을 명령 한 후 세미콜론을 잊지 마세요!

+3

서브 쉘 대신 그룹 명령이 작동해야합니다. –

+2

이것은 시작시 5 초 지연 만 제공합니다. command_b가 command_a가 데이터를 생성하는 것보다 빠르게 데이터를 읽는다면 빠르게 뒤따라 갑자기 나중에 command_a에서 출력 할 수 있습니다. –

+0

@ChrisDodd 맞습니다. 필자가 제시 한 예와 같이 사소한 프로그램은 분명히 구별됩니다. –

0

time_buffered() { 
    delay=$1 
    while read line; do 
     printf "%d %s\n" "$(date +%s)" "$line" 
    done | while read ts line; do 
     now=$(date +%s) 
     if ((now - ts < delay)); then 
      sleep $((now - ts)) 
     fi 
     printf "%s\n" "$line" 
    done 
} 

commandA | time_buffered 5 | commandB 

첫 번째 루프 태그 타임 스탬프 입력의 각 라인을 작동 할 수 즉시 두 번째 루프에 공급한다. 두 번째 루프는 각 회선의 시간 소인을 확인하고 회선을 출력하기 전에 처음 읽은 후 $delay 초까지 필요하면 잠자기 상태가됩니다.

+0

예,하지만 몇 Mb/s 속도로 이진 스트림을 지연 찾고 있습니다. 나는 그것을 코딩하는 것을 고려한다. 그러나 그것이 이미 존재한다면, 나는 그것을 사용할 것이다 ... – rom1v

1

귀하의 질문에 흥미가 생겼습니다. 다시 돌아와서 게임을하기로 결정했습니다. 다음은 Perl의 기본 구현입니다. 아마도 휴대용이 아닙니다 (ioctl), Linux에서만 테스트되었습니다.

기본적인 아이디어는 다음

  • 도 (대기열에 현재 타임 스탬프를 밀어 가능한 입력을 판독 키
  • 로서 현재 타임 스탬프가 모든 X의 마이크로
  • 저장소 해시 각 입력 청크 어레이)
  • 룩업 오래된 타임 스탬프 큐 길이만큼 지연된 경우 해시 데이터를 폐기 + 물품
  • 반복

최대 버퍼 크기

저장된 데이터의 최대 크기가있다. 도달 한 경우 추가 데이터는 쓰기 후에 공간을 사용할 수있게 될 때까지 읽지 않습니다.

성능

그것은 당신의 요구 사항 (몇 MB/s의) 충분히 빨리 아마하지 않습니다. 내 최대 처리량은 639Kb/s였습니다 (아래 참조).

테스트

# Measure max throughput: 
$ pv < /dev/zero | ./buffer_delay.pl > /dev/null 

# Interactive manual test, use two terminal windows: 
$ mkfifo data_fifo 
terminal-one $ cat > data_fifo 
terminal-two $ ./buffer_delay.pl < data_fifo 

# now type in terminal-one and see it appear delayed in terminal-two. 
# It will be line-buffered because of the terminals, not a limitation 
# of buffer_delay.pl 

buffer_delay.pl

#!/usr/bin/perl 
use strict; 
use warnings; 
use IO::Select; 
use Time::HiRes qw(gettimeofday usleep); 
require 'sys/ioctl.ph'; 

$|++; 

my $delay_usec = 3 * 1000000; # (3s) delay in microseconds 
my $buffer_size_max = 10 * 1024 * 1024 ; # (10 Mb) max bytes our buffer is allowed to contain. 
           # When buffer is full, incoming data will not be read 
           # until space becomes available after writing 
my $read_frequency = 10;  # Approximate read frequency in Hz (will not be exact) 

my %buffer;     # the data we are delaying, saved in chunks by timestamp 
my @timestamps;    # keys to %buffer, used as a queue 
my $buffer_size = 0;   # num bytes currently in %buffer, compare to $buffer_size_max 

my $time_slice = 1000000/$read_frequency; # microseconds, min time for each discrete read-step 

my $sel = IO::Select->new([\*STDIN]); 
my $overflow_unread = 0;  # Num bytes waiting when $buffer_size_max is reached 

while (1) { 
    my $now = sprintf "%d%06d", gettimeofday; # timestamp, used to label incoming chunks 

    # input available? 
    if ($overflow_unread || $sel->can_read($time_slice/1000000)) { 

     # how much? 
     my $available_bytes; 
     if ($overflow_unread) { 
      $available_bytes = $overflow_unread; 
     } 
     else { 
      $available_bytes = pack("L", 0); 
      ioctl (STDIN, FIONREAD(), $available_bytes); 
      $available_bytes = unpack("L", $available_bytes); 
     } 

     # will it fit? 
     my $remaining_space = $buffer_size_max - $buffer_size; 
     my $try_to_read_bytes = $available_bytes; 
     if ($try_to_read_bytes > $remaining_space) { 
      $try_to_read_bytes = $remaining_space; 
     } 

     # read input 
     if ($try_to_read_bytes > 0) { 
      my $input_data; 
      my $num_read = read (STDIN, $input_data, $try_to_read_bytes); 
      die "read error: $!" unless defined $num_read; 
      exit if $num_read == 0;  # EOF 
      $buffer{$now} = $input_data; # save input 
      push @timestamps, $now;  # save the timestamp 
      $buffer_size += length $input_data; 
      if ($overflow_unread) { 
       $overflow_unread -= length $input_data; 
      } 
      elsif (length $input_data < $available_bytes) { 
       $overflow_unread = $available_bytes - length $input_data; 
      } 
     } 
    } 

    # write + delete any data old enough 
    my $then = $now - $delay_usec; # when data is old enough 
    while (scalar @timestamps && $timestamps[0] < $then) { 
     my $ts = shift @timestamps; 
     print $buffer{$ts} if defined $buffer{$ts}; 
     $buffer_size -= length $buffer{$ts}; 
     die "Serious problem\n" unless $buffer_size >= 0; 
     delete $buffer{$ts}; 
    } 

    # usleep any remaining time up to $time_slice 
    my $time_left = (sprintf "%d%06d", gettimeofday) - $now; 
    usleep ($time_slice - $time_left) if $time_slice > $time_left; 
} 

의 의견과 제안 사항을 아래 게시 주시기 바랍니다! 이 같은 명령 DIT가 존재하지 보였다으로

+0

아, 당일 내가 그것을 구현했다 : http://stackoverflow.com/a/21078153/1987178 나는 나의 예제 (특히 웹캠 스트림 지연), 그것은 잘 작동합니다. 감사! – rom1v

+0

필자의 프로그램으로'pv' 테스트를했는데, 처리량은 항상 버퍼 크기를 지연으로 나눈 값과 같습니다. 동일한 매개 변수 (3 초 지연, 10MB 버퍼)를 사용하면 3,33Mb/s의 처리량을 얻을 수 있습니다.'pv/dev/null' – rom1v

+0

@ rom1v 예, 나는 또한 그것을 알아 챘습니다. 내 Perl 코드의 경우는 아니지만 훨씬 더 느리고 버퍼 크기에 의존하지 않습니다. 적어도 합리적으로 큰 경우는 아닙니다. 내 시스템에서는 버퍼가 아무리 큰 경우에도 639Kb/sec로 수평을 유지합니다. – grebneke

관련 문제