Add the -P option which executes multiple copies of the specified utility

in parallel. Idea from GNU xargs.
This commit is contained in:
Tim J. Robbins 2002-12-21 10:17:13 +00:00
parent fabf7ce58c
commit 330d23f50e
2 changed files with 57 additions and 19 deletions

View File

@ -57,6 +57,7 @@
.Fl n Ar number .Fl n Ar number
.Op Fl x .Op Fl x
.Oc .Oc
.Op Fl P Ar maxjobs
.Op Fl s Ar size .Op Fl s Ar size
.Op Ar utility Op Ar argument ... .Op Ar utility Op Ar argument ...
.Sh DESCRIPTION .Sh DESCRIPTION
@ -191,6 +192,12 @@ arguments remaining for the last invocation of
The current default value for The current default value for
.Ar number .Ar number
is 5000. is 5000.
.It Fl P Ar maxprocs
Parallel mode: run at most
.Ar maxprocs
invocations of
.Ar utility
at once.
.It Fl p .It Fl p
Echo each command to be executed and ask the user whether it should be Echo each command to be executed and ask the user whether it should be
executed. executed.
@ -273,7 +280,8 @@ utility is expected to be
.St -p1003.2 .St -p1003.2
compliant. compliant.
The The
.Fl J .Fl J ,
.Fl P
and and
.Fl R .Fl R
options are non-standard options are non-standard

View File

@ -76,6 +76,7 @@ static int prompt(void);
static void run(char **); static void run(char **);
static void usage(void); static void usage(void);
void strnsubst(char **, const char *, const char *, size_t); void strnsubst(char **, const char *, const char *, size_t);
static void waitchildren(const char *, int);
static char echo[] = _PATH_ECHO; static char echo[] = _PATH_ECHO;
static char **av, **bxp, **ep, **exp, **xp; static char **av, **bxp, **ep, **exp, **xp;
@ -83,6 +84,9 @@ static char *argp, *bbp, *ebp, *inpline, *p, *replstr;
static const char *eofstr; static const char *eofstr;
static int count, insingle, indouble, pflag, tflag, Rflag, rval, zflag; static int count, insingle, indouble, pflag, tflag, Rflag, rval, zflag;
static int cnt, Iflag, jfound, Lflag, wasquoted, xflag; static int cnt, Iflag, jfound, Lflag, wasquoted, xflag;
static int curprocs, maxprocs;
static volatile int childerr;
extern char **environ; extern char **environ;
@ -121,7 +125,8 @@ main(int argc, char *argv[])
/* 1 byte for each '\0' */ /* 1 byte for each '\0' */
nline -= strlen(*ep++) + 1 + sizeof(*ep); nline -= strlen(*ep++) + 1 + sizeof(*ep);
} }
while ((ch = getopt(argc, argv, "0E:I:J:L:n:pR:s:tx")) != -1) maxprocs = 1;
while ((ch = getopt(argc, argv, "0E:I:J:L:n:P:pR:s:tx")) != -1)
switch(ch) { switch(ch) {
case 'E': case 'E':
eofstr = optarg; eofstr = optarg;
@ -145,6 +150,10 @@ main(int argc, char *argv[])
if ((nargs = atoi(optarg)) <= 0) if ((nargs = atoi(optarg)) <= 0)
errx(1, "illegal argument count"); errx(1, "illegal argument count");
break; break;
case 'P':
if ((maxprocs = atoi(optarg)) <= 0)
errx(1, "max. processes must be >0");
break;
case 'p': case 'p':
pflag = 1; pflag = 1;
break; break;
@ -249,8 +258,10 @@ parse_input(int argc, char *argv[])
switch(ch = getchar()) { switch(ch = getchar()) {
case EOF: case EOF:
/* No arguments since last exec. */ /* No arguments since last exec. */
if (p == bbp) if (p == bbp) {
waitchildren(*argv, 1);
exit(rval); exit(rval);
}
goto arg1; goto arg1;
case ' ': case ' ':
case '\t': case '\t':
@ -327,8 +338,10 @@ arg2:
*xp++ = *avj; *xp++ = *avj;
} }
prerun(argc, av); prerun(argc, av);
if (ch == EOF || foundeof) if (ch == EOF || foundeof) {
waitchildren(*argv, 1);
exit(rval); exit(rval);
}
p = bbp; p = bbp;
xp = bxp; xp = bxp;
count = 0; count = 0;
@ -467,10 +480,8 @@ prerun(int argc, char *argv[])
static void static void
run(char **argv) run(char **argv)
{ {
volatile int childerr;
char **avec;
pid_t pid; pid_t pid;
int status; char **avec;
/* /*
* If the user wants to be notified of each command before it is * If the user wants to be notified of each command before it is
@ -512,17 +523,35 @@ exec:
childerr = errno; childerr = errno;
_exit(1); _exit(1);
} }
pid = waitpid(pid, &status, 0); curprocs++;
if (pid == -1) waitchildren(*argv, 0);
err(1, "waitpid"); }
/* If we couldn't invoke the utility, exit. */
if (childerr != 0) static void
err(childerr == ENOENT ? 127 : 126, "%s", *argv); waitchildren(const char *name, int waitall)
/* If utility signaled or exited with a value of 255, exit 1-125. */ {
if (WIFSIGNALED(status) || WEXITSTATUS(status) == 255) pid_t pid;
exit(1); int status;
if (WEXITSTATUS(status))
rval = 1; while ((pid = wait3(&status, !waitall && curprocs < maxprocs ?
WNOHANG : 0, NULL)) > 0) {
curprocs--;
/* If we couldn't invoke the utility, exit. */
if (childerr != 0) {
errno = childerr;
err(errno == ENOENT ? 127 : 126, "%s", name);
}
/*
* If utility signaled or exited with a value of 255,
* exit 1-125.
*/
if (WIFSIGNALED(status) || WEXITSTATUS(status) == 255)
exit(1);
if (WEXITSTATUS(status))
rval = 1;
}
if (pid == -1 && errno != ECHILD)
err(1, "wait3");
} }
/* /*
@ -564,6 +593,7 @@ usage(void)
{ {
fprintf(stderr, fprintf(stderr,
"usage: xargs [-0pt] [-E eofstr] [-I replstr [-R replacements]] [-J replstr]\n" "usage: xargs [-0pt] [-E eofstr] [-I replstr [-R replacements]] [-J replstr]\n"
" [-L number] [-n number [-x] [-s size] [utility [argument ...]]\n"); " [-L number] [-n number [-x] [-P maxprocs] [-s size]\n"
" [utility [argument ...]]\n");
exit(1); exit(1);
} }