質問: タイミングファイルなしでscriptreplayを使用する scriptを使用してターミナルセッションを記録しましたが、誤ってタイミングファイルを削除してしまいました。デフォルトの入力速度などを想定して、タイミングファイルなしでscriptreplayを使用することは可能ですか?または、scriptの録音を再生できる他のプログラムはありますか?
回答: githubのscriptreplay_ngプロジェクトによって提供されるscriptreplayperlスクリプトを使用できます: https://github.com/scoopex/scriptreplay_ng :#!/usr/bin/env perl # # scriptreplay - play back typescript of terminal session # # # author(s): # joey hess <joey@kitenet.net> # marc schoechlin <ms@256bit.org> # hendrik brueckner <hb-perl@256bit.org> # # use strict; use warnings; use file::basename; use getopt::long; use io::select; use posix; use term::readkey; sub main(); sub show_usage(); sub __exit($;@); sub open_expr($); my $progname = fileparse($0, qr/\.[^.]+/); $sig{__warn__} = sub { print stderr "$progname: $_[0]"; }; $sig{__die__} = sub { print stderr "$progname: $_[0]"; __exit 254; }; sub main() { my $time_file; my $script_file; my $accel = 1; # parse command line options unless (getoptions("t|timing=s" => \$time_file, "a|accelerate=f" => \$accel, "<>" => sub { $script_file = shift; }, "h|help" => sub { show_usage(); exit 0; })) { show_usage(); exit 1; } # check parameters die "you need to specify a script file (see also option '-h')\n" unless defined $script_file; die "acceleration factor must be greater than 0\n" unless $accel > 0; # open script_file open (script, open_expr($script_file)) or die "cannot open typescript file $script_file: $!\n"; unless (<script> =~ /^s.*:.*/i) { die "$script_file is not a valid typescript from script(1)\n"; } # automatic discovery of a (compressed) time_file unless ($time_file) { my $tmp = $script_file; if ($tmp =~ /(\.(?:bz2|gz|lz|lzma))$/) { $tmp =~ s/($1)$/.timing$1/; } else { $tmp = $tmp . ".timing"; } $time_file = $tmp if -r $tmp; } # open time_file if ($time_file) { open (timing, open_expr($time_file)) or die "cannot open timing data file $time_file: $!\n"; } # enable autoflush select stderr; $| = 1; select stdout; $| = 1; # set up acceleration $accel = 1 / $accel; # term::readkey setup readmode('noecho'); readmode('cbreak'); # declare timing and replay block variables my $replay_time = 0; # time of the typescript my $accel_time = 0; # accelerated typescript my ($block, $oldblock) = ("", ""); # script block my ($delay, $blocksize) = (.005, 1); # timing parameter # install signal handler to reset term::readkey modes my $sigaction = posix::sigaction->new(sub { __exit 0; }, posix::sigset->new(), &posix::sa_nodefer); posix::sigaction(&posix::sigint, $sigaction); posix::sigaction(&posix::sigterm, $sigaction); # use select for timeouts and to monitor stdin activity my $select = io::select->new(); $select->add(\*stdin); # start replaying... replay: while (1) { if ($time_file) { my $timing_line = <timing>; last replay unless defined $timing_line; # skip this line if this line contains shell tracing information next replay if $timing_line =~ /^\+\+/; # this line doesn't seem to a valid timing, somthing is wrong here if ($timing_line !~ /([.\d]+)\s+(\d+)/){ print "error: malformed timing line '".$timing_line."'\n"; last replay } ($delay, $blocksize) = ($1, $2); } # calculate timeout my $timeout = $delay * $accel**3; # count delays (may vary depending on select) $replay_time += $delay; $accel_time += $timeout; # sleep, unless the delay is really tiny. really tiny delays # cannot be accurately done, because the system calls in this # loop will have more overhead. the 0.0001 is arbitrary, but # works fairly well. my @fdset = $select->can_read($timeout) if $timeout > 0.0001; # handle read terminal keys if (@fdset) { my $key = readkey(0); $accel += 0.1 if $key =~ /-|d/i; $accel -= 0.1 if $key =~ /\+|i/i && $accel > 0.11; last replay if $key =~ /q|f/i; if ($key =~ /s|p/i) { while (readkey(0) =~ /c/i) { next; } } } # read typescript my $cnt; unless (defined($cnt = read(script, $block, $blocksize))) { warn "read failure on script file ($script_file): $!"; last replay; } last replay unless $cnt; # eof print $oldblock; # write delayed block $oldblock = $block; } print $oldblock; close timing if $time_file; close script; __exit 0, $replay_time, $accel_time; } sub show_usage() { print <<eousage; usage: $progname [-h|--help] $progname [-a <num>] [-t <timing file>] <typescript> options: -t, --timing path to timing data file. -a, --accelerate acceleration of typescript timing (> 0). -h, --help print this help, then exit. detailed documentation: perldoc $0 eousage } sub __exit($;@) { my $exitcode = shift(); my @times = @_; readmode('normal'); if (@times) { printf "\n$progname: %s %5.0f seconds (%2.0f minutes)\n", "typescript time (normal):", $times[0], $times[0]/60; printf "$progname: %s %5.0f seconds (%2.0f minutes)\n", "typescript time (accel) :", $times[1], $times[1]/60; } exit $exitcode; } sub open_expr($) { $_ = shift(); /\.bz2$/i and return "bzcat $_|"; # block-sorting file compressor /\.gz$/i and return "zcat $_|"; # lempel-ziv coding (lz77) /\.lz(?:ma)?$/i and return "lzcat $_|"; # lempel-ziv-markov chain return "<$_"; } # start script &main(); __data__ =head1 name scriptreplay - play back typescript of terminal session =head1 synopsis b<scriptreplay> -h|--help b<scriptreplay> [-a|--accelerate <num>] [-t|--timing <timingfile>] <typescript> =head1 description b<scriptreplay> replays a typescript of a terminal session; optionally, using timing data to ensure realistic typing and output delays. the timing data consists of two fields, separated by a space. the first field indicates how much time elapsed since the previous output. the second field indicates how many characters were output this time. i<typescript> is the path to the typescript file. if the file i<typescript>.timing exists then it is automatically used as timing data file. use parameter b<-t> or b<--timing> to specify an alternative timing data file. this version of b<scriptreplay> supports reading of compressed i<typescript> files. if i<timingfile> is not specified, b<scriptreplay> tries to open a timing data file that uses the same compression algorithm as i<typescript>. the decompression method is determined by examining the file extension of the i<typescript> file. recognized file extensions of compressed i<typescript> files are: c<bz2>, c<gz>, c<lz> or c<lzma>. =head2 controlling the playback =over 4 =item * "-" or "d" decreases display speed. =item * "+" or "i" increases display speed. =item * "s" or "p" pauses the playback; and "c" continues again. =item * "f" or "q" stops the playback and exits b<scriptreplay>. =back pressing any other key jumps to the next output (useful if there is no output activity due to a long delay). =head1 options =over 8 =item b<-a>, b<--accelerate> i<num> accelerates timing by factor i<num>. i<num> must be greater than 0. a i<num> value less than 1 slows down the playback speed; and a value greater than 1 increases the playback speed. =item b<-t>, b<--timing> i<timingfile> specify the file path to the timing data file. =back =head1 examples =head2 create a new typescript with timing data user@caladan:~$ script -t typescript 2>typescript.timing script started, file is typescript user@caladan:~$ ls ... user@caladan:~$ exit script done, file is typescript =head2 replay a typescript user@arrakis:~$ scriptreplay typescript user@caladan:~$ ls ... user@caladan:~$ exit scriptreplay: typescript time (normal): 14 seconds ( 0 minutes) scriptreplay: typescript time (accel) : 1 seconds ( 0 minutes) =head1 notes the playback might not work properly if the typescript contains output from applications that have been recorded with different termio settings and/or terminal window sizes. =head1 copyright this program is in the public domain. =head1 authors joey hess <joey@kitenet.net> marc schoechlin <ms@256bit.org> hendrik brueckner <hb-perl@256bit.org> =head1 see also script(1), bzcat(1), zcat(1), lzcat(1) =cut __end__ # vim: set ai noet ts=8 sw=8 tw=80: