Je souhaite ajouter un horodatage à chaque ligne de sortie d'une commande. Par exemple:
foo
bar
baz
deviendrait
[2011-12-13 12:20:38] foo
[2011-12-13 12:21:32] bar
[2011-12-13 12:22:20] baz
... où l'heure est préfixée est l'heure à laquelle la ligne a été imprimée. Comment puis-je atteindre cet objectif?
Réponses:
moreutils comprend
ts
ce qui le fait assez bien:command | ts '[%Y-%m-%d %H:%M:%S]'
Cela élimine également le besoin d'une boucle, chaque ligne de sortie ayant un horodatage.
Vous voulez savoir quand ce serveur est revenu vous avez redémarré? Courez
ping | ts
, problème résolu: D.la source
tail -f /tmp/script.results.txt | ts
ssh -v 127.0.0.1 2>&1 | ts
-s
est utile. Comme cela affiche le runtime de la commande. Personnellement, j'aime utiliser les deuxts
etts -s
en même temps. On dirait quelque chose comme ceci:command | ts -s '(%H:%M:%.S)]' | ts '[%Y-%m-%d %H:%M:%S'
. Ceci ajoute les lignes de journal comme ceci:[2018-12-04 08:31:00 (00:26:28.267126)] Hai <3
Tout d'abord, si vous vous attendez à ce que ces horodatages représentent réellement un événement, gardez à l'esprit que, dans la mesure où de nombreux programmes effectuent une mise en mémoire tampon des lignes (certains de manière plus agressive que d'autres), il est important de penser à cela aussi près du temps que la ligne d'origine aurait. été imprimé plutôt que l’horodatage d’une action ayant lieu.
Vous pouvez également vérifier que votre commande ne dispose pas déjà d'une fonctionnalité intégrée dédiée à cela. Par exemple,
ping -D
existe dans certainesping
versions et affiche le temps écoulé depuis l'époque Unix avant chaque ligne. Si votre commande ne contient pas sa propre méthode, vous pouvez utiliser quelques méthodes et outils, entre autres:Shell POSIX
Gardez à l'esprit que, comme de nombreux shell stockent leurs chaînes en interne en tant que chaînes, si l'entrée contient le caractère nul (
\0
), la ligne peut se terminer prématurément.GNU awk
Perl
Python
Rubis
la source
stdbuf -o 0
, mais si le programme gère manuellement sa mise en tampon de sortie, cela n’aidera pas (sauf s’il existe une option pour désactiver / réduire la taille du tampon de sortie).python -u
... for x in sys.stdin
itération sur les lignes sans les mettre d'abord en mémoire tampon.Pour une mesure delta ligne par ligne, essayez gnomon .
la source
ts
utilisation de processus en direct. Whilets
est mieux adapté aux processus non interactifs.Le message de Ryan fournit une idée intéressante, mais il échoue à plusieurs égards. En testant avec
tail -f /var/log/syslog | xargs -L 1 echo $(date +'[%Y-%m-%d %H:%M:%S]') $1
, j’ai remarqué que l’horodatage reste le même, même s’ilstdout
arrive plus tard avec une différence en secondes. Considérez cette sortie:La solution proposée est similaire, mais fournit une horodatage correcte et utilise un peu plus de portabilité
printf
que deecho
Pourquoi
bash -c '...' bash
? En raison de l'-c
option, le premier argument est attribué à$0
et ne sera pas affiché dans la sortie. Consultez la page de manuel de votre shell pour la description correcte de-c
Tester cette solution avec
tail -f /var/log/syslog
et (comme vous pouvez probablement le deviner) en vous déconnectant et en vous reconnectant à mon réseau wifi, a montré le bon horodatage fourni par les messagesdate
etsyslog
Bash pourrait être remplacé par n’importe quelle coquille semblable au bourne, pourrait être fait avec l’un
ksh
ou l’ autredash
, du moins ceux qui ont une-c
option.Problèmes potentiels:
La solution nécessite la
xargs
mise à disposition, disponible sur les systèmes compatibles POSIX, de sorte que la plupart des systèmes de type Unix doivent être couverts. De toute évidence, cela ne fonctionnera pas si votre système n’est pas compatible POSIX ou n’a pasGNU findutils
la source
J'aurais préféré commenter ci-dessus mais je ne peux pas, à la réputation. Quoi qu’il en soit, l’échantillon Perl ci-dessus peut être décompressé comme suit:
Le premier '$ |' unbuffers STDOUT. Le second définit stderr comme canal de sortie par défaut actuel et le désamorce. Puisque select renvoie le paramètre original de $ |, en repliant la sélection dans une sélection, nous réinitialisons également $ | à sa valeur par défaut, STDOUT.
Et oui, vous pouvez couper et coller en l'état. Je l'ai doublé pour plus de lisibilité.
Et si vous voulez vraiment être précis (et que Time :: Hires est installé):
la source
La plupart des réponses suggèrent d'utiliser
date
, mais c'est assez lent. Si votre version de bash est supérieure à 4.2.0, il est préférable de l'utiliser à laprintf
place, c'est une commande intégrée à bash. Si vous devez prendre en charge des versions anciennes de bash, vous pouvez créer unelog
fonction qui dépend de la version de bash:Voir les différences de vitesse:
UPD: au lieu de
$(date +"${TIMESTAMP_FORMAT}")
cela, il vaut mieux utiliser$(exec date +"${TIMESTAMP_FORMAT}")
ou même$(exec -c date +"${TIMESTAMP_FORMAT}")
accélérer l'exécution.la source
Vous pouvez le faire avec
date
etxargs
:Explication:
xargs -L 1
indique à xargs d'exécuter la commande précédente pour chaque ligne d'entrée et passe dans la première ligne comme il le fait.echo `date +'[%Y-%m-%d %H:%M:%S]'` $1
fait essentiellement écho à la date avec l'argument d'entrée à la fin de celui-cila source
$1
. Ce n'est pas bon style. Citez toujours les variables. De plus, vous utilisezecho
, ce qui n’est pas portable. Tout va bien, mais peut ne pas fonctionner correctement sur certains systèmes.date
réévaluer chaque ligne, ou est-ce à peu près sans espoir?