mirror of
https://git.freebsd.org/src.git
synced 2026-01-11 19:57:22 +00:00
Add ts(1) command
Add /usr/bin/ts, a command that timestamps each line of its stdin before it is being printed to stdout. A typical use case is to profile shell scripts. Obtained from: OpenBSD 7.2 Relnotes: yes Reviewed by: adrian Differential Revision: https://reviews.freebsd.org/D35694
This commit is contained in:
parent
a49621c1d0
commit
3d516b8531
4 changed files with 291 additions and 0 deletions
112
contrib/ts/ts.1
Normal file
112
contrib/ts/ts.1
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
.\" $OpenBSD: ts.1,v 1.6 2022/06/30 21:40:41 jmc Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2022 Job Snijders <job@openbsd.org>
|
||||
.\"
|
||||
.\" Permission to use, copy, modify, and distribute this software for any
|
||||
.\" purpose with or without fee is hereby granted, provided that the above
|
||||
.\" copyright notice and this permission notice appear in all copies.
|
||||
.\"
|
||||
.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
.\"
|
||||
.Dd June 30, 2022
|
||||
.Dt TS 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm ts
|
||||
.Nd timestamp input
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl i | s
|
||||
.Op Fl m
|
||||
.Op Ar format
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
utility prepends a timestamp to each line of standard input and writes
|
||||
it to standard output.
|
||||
.Pp
|
||||
The options are as follows:
|
||||
.Bl -tag -width Ds
|
||||
.It Fl i
|
||||
Display time elapsed since the last timestamp.
|
||||
.It Fl m
|
||||
Display timestamps derived from a strictly linearly increasing clock.
|
||||
Without
|
||||
.Fl m ,
|
||||
timestamps reflect the current date and time, including time jumps if the
|
||||
system time is changed.
|
||||
.It Fl s
|
||||
Display time elapsed since the start of the program.
|
||||
.El
|
||||
.Pp
|
||||
The optional
|
||||
.Ar format
|
||||
argument controls how the timestamp is displayed, according to the conversion
|
||||
specifications described in the
|
||||
.Xr strftime 3
|
||||
manual page.
|
||||
The default format is
|
||||
.Qq %b %d %H:%M:%S ;
|
||||
or
|
||||
.Qq %H:%M:%S
|
||||
if one of the
|
||||
.Fl i
|
||||
or
|
||||
.Fl s
|
||||
options is used.
|
||||
.Pp
|
||||
Some additional conversion specifications are also supported
|
||||
to append microsecond resolution:
|
||||
.Cm %.S ,
|
||||
.Cm %.s ,
|
||||
and
|
||||
.Cm %.T ;
|
||||
which are similar to
|
||||
.Cm %S ,
|
||||
.Cm %s ,
|
||||
and
|
||||
.Cm \&%T .
|
||||
Examples:
|
||||
.Qq 10.00001 ,
|
||||
.Qq 1656427781.00001 ,
|
||||
and
|
||||
.Qq 4:20:00.00001 .
|
||||
.Sh EXAMPLES
|
||||
.Bd -literal -offset indent
|
||||
$ (echo foo; sleep 2; echo bar) | ts
|
||||
Jun 28 12:13:38 foo
|
||||
Jun 28 12:13:40 bar
|
||||
|
||||
$ ls | ts -i %.S
|
||||
00.000452 CVS
|
||||
00.000595 Makefile
|
||||
00.000004 ts.1
|
||||
00.000004 ts.c
|
||||
.Ed
|
||||
.Sh SEE ALSO
|
||||
.Xr strftime 3
|
||||
.Sh HISTORY
|
||||
A
|
||||
.Nm
|
||||
utility first appeared in the moreutils collection by Joey Hess, and was
|
||||
rewritten from scratch for
|
||||
.Ox 7.2 .
|
||||
.Pp
|
||||
It was imported to
|
||||
.Fx
|
||||
by
|
||||
.An -nosplit
|
||||
.An Juraj Lutter Aq Mt otis@FreeBSD.org .
|
||||
.Sh AUTHORS
|
||||
This
|
||||
.Nm
|
||||
utility was written by
|
||||
.An Job Snijders Aq Mt job@openbsd.org
|
||||
and
|
||||
.An Claudio Jeker Aq Mt claudio@openbsd.org .
|
||||
171
contrib/ts/ts.c
Normal file
171
contrib/ts/ts.c
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
/* $OpenBSD: ts.c,v 1.7 2022/07/06 07:59:03 claudio Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2022 Job Snijders <job@openbsd.org>
|
||||
* Copyright (c) 2022 Claudio Jeker <claudio@openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
|
||||
static const char *format = "%b %d %H:%M:%S";
|
||||
static char *buf;
|
||||
static char *outbuf;
|
||||
static size_t bufsize;
|
||||
|
||||
static void fmtfmt(const struct timespec *);
|
||||
static void __dead2 usage(void);
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int iflag, mflag, sflag;
|
||||
int ch, prev;
|
||||
struct timespec start, now, utc_offset, ts;
|
||||
clockid_t clock = CLOCK_REALTIME;
|
||||
|
||||
iflag = mflag = sflag = 0;
|
||||
|
||||
while ((ch = getopt(argc, argv, "ims")) != -1) {
|
||||
switch (ch) {
|
||||
case 'i':
|
||||
iflag = 1;
|
||||
format = "%H:%M:%S";
|
||||
clock = CLOCK_MONOTONIC;
|
||||
break;
|
||||
case 'm':
|
||||
mflag = 1;
|
||||
clock = CLOCK_MONOTONIC;
|
||||
break;
|
||||
case 's':
|
||||
sflag = 1;
|
||||
format = "%H:%M:%S";
|
||||
clock = CLOCK_MONOTONIC;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if ((iflag && sflag) || argc > 1)
|
||||
usage();
|
||||
|
||||
if (argc == 1)
|
||||
format = *argv;
|
||||
|
||||
bufsize = strlen(format);
|
||||
if (bufsize > SIZE_MAX / 10)
|
||||
errx(1, "format string too big");
|
||||
|
||||
bufsize *= 10;
|
||||
if ((buf = calloc(1, bufsize)) == NULL)
|
||||
err(1, NULL);
|
||||
if ((outbuf = calloc(1, bufsize)) == NULL)
|
||||
err(1, NULL);
|
||||
|
||||
/* force UTC for interval calculations */
|
||||
if (iflag || sflag)
|
||||
if (setenv("TZ", "UTC", 1) == -1)
|
||||
err(1, "setenv UTC");
|
||||
|
||||
clock_gettime(clock, &start);
|
||||
clock_gettime(CLOCK_REALTIME, &utc_offset);
|
||||
timespecsub(&utc_offset, &start, &utc_offset);
|
||||
|
||||
for (prev = '\n'; (ch = getchar()) != EOF; prev = ch) {
|
||||
if (prev == '\n') {
|
||||
clock_gettime(clock, &now);
|
||||
if (iflag || sflag)
|
||||
timespecsub(&now, &start, &ts);
|
||||
else if (mflag)
|
||||
timespecadd(&now, &utc_offset, &ts);
|
||||
else
|
||||
ts = now;
|
||||
fmtfmt(&ts);
|
||||
if (iflag)
|
||||
start = now;
|
||||
}
|
||||
if (putchar(ch) == EOF)
|
||||
break;
|
||||
}
|
||||
|
||||
if (fclose(stdout))
|
||||
err(1, "stdout");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __dead2
|
||||
usage(void)
|
||||
{
|
||||
fprintf(stderr, "usage: %s [-i | -s] [-m] [format]\n", getprogname());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* yo dawg, i heard you like format strings
|
||||
* so i put format strings in your user supplied input
|
||||
* so you can format while you format
|
||||
*/
|
||||
static void
|
||||
fmtfmt(const struct timespec *ts)
|
||||
{
|
||||
struct tm *tm;
|
||||
char *f, us[7];
|
||||
|
||||
if ((tm = localtime(&ts->tv_sec)) == NULL)
|
||||
err(1, "localtime");
|
||||
|
||||
snprintf(us, sizeof(us), "%06ld", ts->tv_nsec / 1000);
|
||||
strlcpy(buf, format, bufsize);
|
||||
f = buf;
|
||||
|
||||
do {
|
||||
while ((f = strchr(f, '%')) != NULL && f[1] == '%')
|
||||
f += 2;
|
||||
|
||||
if (f == NULL)
|
||||
break;
|
||||
|
||||
f++;
|
||||
if (f[0] == '.' &&
|
||||
(f[1] == 'S' || f[1] == 's' || f[1] == 'T')) {
|
||||
size_t l;
|
||||
|
||||
f[0] = f[1];
|
||||
f[1] = '.';
|
||||
f += 2;
|
||||
l = strlen(f);
|
||||
memmove(f + 6, f, l + 1);
|
||||
memcpy(f, us, 6);
|
||||
f += 6;
|
||||
}
|
||||
} while (*f != '\0');
|
||||
|
||||
if (strftime(outbuf, bufsize, buf, tm) == 0)
|
||||
errx(1, "strftime");
|
||||
|
||||
fprintf(stdout, "%s ", outbuf);
|
||||
if (ferror(stdout))
|
||||
exit(1);
|
||||
}
|
||||
|
|
@ -155,6 +155,7 @@ SUBDIR= alias \
|
|||
tr \
|
||||
true \
|
||||
truncate \
|
||||
ts \
|
||||
tsort \
|
||||
tty \
|
||||
uname \
|
||||
|
|
|
|||
7
usr.bin/ts/Makefile
Normal file
7
usr.bin/ts/Makefile
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
.PATH: ${SRCTOP}/contrib/ts
|
||||
|
||||
PROG= ts
|
||||
SRCS= ts.c
|
||||
MAN= ts.1
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
Loading…
Add table
Reference in a new issue