From aaec832c865bfd4878cb8bcdb067d98dc6febd6e Mon Sep 17 00:00:00 2001 From: Leah Neukirchen Date: Mon, 10 Jul 2017 16:52:57 +0200 Subject: xe: add -L for output line buffering We spawn one logging process per job, this is not very efficient, but easy to implement. --- xe.1 | 11 ++++++++++- xe.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 63 insertions(+), 6 deletions(-) diff --git a/xe.1 b/xe.1 index 1e0d7d1..0e2fde6 100644 --- a/xe.1 +++ b/xe.1 @@ -6,7 +6,7 @@ .Nd run command for each line or argument .Sh SYNOPSIS .Nm -.Op Fl 0FRnv +.Op Fl 0FLRnv .Op Fl I Ar arg .Op Fl N Ar maxargs .Op Fl j Ar maxjobs @@ -84,6 +84,15 @@ is the default) .It Fl F Fatal: stop and exit when a command execution failed. +.It Fl L +Run the commands with line-buffered output; +lines from two jobs will not interleave. +When used with +.Fl vv , +also prefix each line with the PID +in such a manner that the output can be piped to +.Sq Li sort -snk1 +to group it by job. .It Fl R Return with status 122 when no arguments have been passed (instead of 0, the default). diff --git a/xe.c b/xe.c index 2b6bf68..0989f3a 100644 --- a/xe.c +++ b/xe.c @@ -29,7 +29,7 @@ static int maxatonce = 1; static int maxjobs = 1; static int runjobs = 0; static int failed = 0; -static int Aflag, Fflag, Rflag, aflag, nflag, vflag; +static int Aflag, Fflag, Lflag, Rflag, aflag, nflag, vflag; static long iterations = 0; static FILE *traceout; static FILE *input; @@ -203,7 +203,7 @@ pusharg(const char *a) static int run() { - pid_t pid; + pid_t pid, lpid; while (runjobs >= maxjobs) mywait(); @@ -218,6 +218,12 @@ run() return 0; } + int pipefd[2]; + if (Lflag) { + if (pipe(pipefd) < 0) + exit(126); + } + pid = fork(); if (pid == 0) { // in child char iter[32]; @@ -232,14 +238,52 @@ run() close(fd); } } + + if (Lflag) { + if (dup2(pipefd[1], 1) < 0) + exit(126); + close(pipefd[0]); + close(pipefd[1]); + } + execvp(args[0], args); fprintf(stderr, "xe: %s: %s\n", args[0], strerror(errno)); exit(errno == ENOENT ? 127 : 126); } - if (pid < 0) exit(126); + if (Lflag) { + lpid = fork(); + if (lpid == 0) { // in line-logging child + char *line = 0; + size_t linelen = 0; + + close(0); + close(pipefd[1]); + FILE *input = fdopen(pipefd[0], "r"); + if (!input) + exit(126); + + setvbuf(stdout, 0, _IOLBF, 0); + + while (1) { + int rd = getdelim(&line, &linelen, '\n', input); + if (rd == -1) + exit(0); + + if (vflag > 1) + printf("%ld= ", (long)pid); + fwrite(line, 1, rd, stdout); + }; + } + if (lpid < 0) + exit(126); + + close(pipefd[0]); + close(pipefd[1]); + } + if (vflag) { if (vflag > 1) fprintf(traceout, "%ld> ", (long)pid); @@ -329,11 +373,12 @@ main(int argc, char *argv[], char *envp[]) traceout = stdout; - while ((c = getopt(argc, argv, "+0A:FI:N:Raf:j:ns:v")) != -1) + while ((c = getopt(argc, argv, "+0A:FI:LN:Raf:j:ns:v")) != -1) switch(c) { case '0': delim = '\0'; break; case 'A': argsep = optarg; Aflag++; break; case 'I': replace = optarg; break; + case 'L': Lflag++; break; case 'N': maxatonce = atoi(optarg); break; case 'F': Fflag++; break; case 'R': Rflag++; break; @@ -345,7 +390,7 @@ main(int argc, char *argv[], char *envp[]) case 'v': vflag++; traceout = stderr; break; default: fprintf(stderr, - "Usage: %s [-0FRnv] [-I arg] [-N maxargs] [-j maxjobs] COMMAND...\n" + "Usage: %s [-0FLRnv] [-I arg] [-N maxargs] [-j maxjobs] COMMAND...\n" " | -f ARGFILE COMMAND...\n" " | -s SHELLSCRIPT\n" " | -a COMMAND... -- ARGS...\n" @@ -358,6 +403,9 @@ main(int argc, char *argv[], char *envp[]) if (!children) exit(1); + if (Lflag && vflag > 1) + traceout = stdout; + if (aflag || Aflag) { input = 0; } else if (!fflag || strcmp("-", fflag) == 0) { -- cgit 1.4.1