Hallo Martin.
Ich möchte in der Ausgabe in jeder ausgegebenen Zeile einen Zeitstempel haben.
cat datei.txt | while read i; do printf „%s: $i\n“ $(date +%X.%N); done
Der Befehl scheint erst einige Ausgabe zu Buffern bevor sie ausgegeben wird. Das führt dazu, dass viele Zeilen die gleiche Zeit bekommen, obwohl sie mit 10s Unterschied ausgegeben werden wenn ich das Programm normal starte…
Die verwendete Pipe der Form „a | b“ verwendet Zeilenpufferung ,
d.h. erst wenn der Prozess a eine komplette Zeile mit abschließendem Newline geschrieben hat, wird die Zeile an Prozess b weitergereicht.
Für Dich heißt das, das obige Lösung einen Zeitstempel erzeugt
für das vollständige Schreiben einer Ergebniszeile von Prozess a.
Mit folgendem Beispiel-Skript - slow-output.sh - als Erzeuger a,
wird die Funktionsweise deutlich:
#!/bin/bash
# Datei: slow-output.sh
echo -n "1a) $(date +%X.%N) ... "
sleep 5
echo "1b) $(date +%X.%N)"
echo -n "2a) $(date +%X.%N) ... "
sleep 5
echo "2b) $(date +%X.%N)"
Zudem scheint das printf noch eine Ausgabepufferung einzufügen,
deshalb habe ich es durch ein einfaches echo ersetzt:
$ ./slow-output.sh | while read i; do echo "$(date +%X.%N): $i"; done
01:18:42.468750000: 1a) 01:18:37.078125000 ... 1b) 01:18:42.312500000
01:18:47.812500000: 2a) 01:18:42.453125000 ... 2b) 01:18:47.687500000
Wie Du siehst entspricht der von echo hinzugefügte Zeitstempel bis auf wenige Millisekunden dem Zeitstempel b).
Willst Du einen Zeitstempel für den Beginn der Prozessausgabe von
a haben, wird es etwas komplizierter. Hier hilft folgendes Perl-Skript
timestamper.pl:
#!/usr/bin/perl -w
# Datei: timestamper.pl
# modules:
use strict;
use Term::ReadKey;
use Time::localtime; # for easier time member access
use Time::HiRes; # to get current microseconds
# variables:
my $firstKey;
my $remainingLine;
while (!eof()) { # run until input channel gets closed
ReadMode('cbreak'); # switch to single-key processing
while (not defined ($firstKey = ReadKey(-1))) {} # wait for first key of line
my ($seconds, $microseconds) = Time::HiRes::gettimeofday();
my $timestamp = localtime($seconds);
my $time = sprintf("%02d:%02d:%02d.%06d", $timestamp-\>hour, $timestamp-\>min, $timestamp-\>sec, $microseconds);
print "${time}: $firstKey";
ReadMode('normal'); # back to line-processing
$remainingLine = ReadLine 0;
print $remainingLine;
}
Die Ausgabe dazu:
$ ./slow-output.sh | ./timestamper.pl
01:21:47.343750: 1a) 01:21:47.203125000 ... 1b) 01:21:52.453125000
01:21:52.562500: 2a) 01:21:52.562500000 ... 2b) 01:21:57.812500000
Nun entspricht der Zeitstempel knapp dem von a).
Gruß,
-Andreas.