diff --git a/bin/sh/builtins.def b/bin/sh/builtins.def index f06a98bc4bd7..2410425094ee 100644 --- a/bin/sh/builtins.def +++ b/bin/sh/builtins.def @@ -49,7 +49,8 @@ # # NOTE: bltincmd must come first! -bltincmd command +bltincmd builtin +commandcmd command #alloccmd alloc bgcmd -j bg breakcmd break continue diff --git a/bin/sh/eval.c b/bin/sh/eval.c index 5d8f309f32bc..4e1079b16e50 100644 --- a/bin/sh/eval.c +++ b/bin/sh/eval.c @@ -42,6 +42,7 @@ static char sccsid[] = "@(#)eval.c 8.9 (Berkeley) 6/8/95"; #include __FBSDID("$FreeBSD$"); +#include #include #include #include /* For WIFSIGNALED(status) */ @@ -747,7 +748,9 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd) && (cmdentry.cmdtype != CMDBUILTIN || cmdentry.u.index == CDCMD || cmdentry.u.index == DOTCMD - || cmdentry.u.index == EVALCMD))) { + || cmdentry.u.index == EVALCMD)) + || (cmdentry.cmdtype == CMDBUILTIN && + cmdentry.u.index == COMMANDCMD)) { jp = makejob(cmd, 1); mode = cmd->ncmd.backgnd; if (flags & EV_BACKCMD) { @@ -869,7 +872,8 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd) #ifndef NO_HISTORY || cmdentry.u.index == HISTCMD #endif - || cmdentry.u.index == EXECCMD) + || cmdentry.u.index == EXECCMD + || cmdentry.u.index == COMMANDCMD) exraise(e); FORCEINTON; } @@ -986,6 +990,54 @@ breakcmd(int argc, char **argv) return 0; } +/* + * The `command' command. + */ +int +commandcmd(int argc, char **argv) +{ + static char stdpath[] = _PATH_STDPATH; + struct jmploc loc, *old; + struct strlist *sp; + char *path; + int ch; + + for (sp = cmdenviron; sp ; sp = sp->next) + setvareq(sp->text, VEXPORT|VSTACK); + path = pathval(); + + optind = optreset = 1; + while ((ch = getopt(argc, argv, "p")) != -1) { + switch (ch) { + case 'p': + path = stdpath; + break; + case '?': + default: + error("unknown option: -%c", optopt); + } + } + argc -= optind; + argv += optind; + + if (argc != 0) { + old = handler; + handler = &loc; + if (setjmp(handler->loc) == 0) + shellexec(argv, environment(), path, 0); + handler = old; + if (exception == EXEXEC) + exit(exerrno); + exraise(exception); + } + + /* + * Do nothing successfully if no command was specified; + * ksh also does this. + */ + exit(0); +} + /* * The return command. diff --git a/bin/sh/eval.h b/bin/sh/eval.h index 77dbbab77c1b..ff30c0c1695a 100644 --- a/bin/sh/eval.h +++ b/bin/sh/eval.h @@ -60,6 +60,7 @@ int returncmd(int, char **); int falsecmd(int, char **); int truecmd(int, char **); int execcmd(int, char **); +int commandcmd(int, char **); /* in_function returns nonzero if we are currently evaluating a function */ #define in_function() funcnest diff --git a/bin/sh/sh.1 b/bin/sh/sh.1 index 20a9664a97ed..369b5f3d75c3 100644 --- a/bin/sh/sh.1 +++ b/bin/sh/sh.1 @@ -1274,7 +1274,7 @@ suitable for reinput to the shell. Continue the specified jobs (or the current job if no jobs are given) in the background. -.It Ic command Ar cmd Op Ar arg ... +.It Ic builtin Ar cmd Op Ar arg ... Execute the specified builtin command, .Ar cmd . This is useful when the user wishes to override a shell function @@ -1333,6 +1333,26 @@ A synonym for the .Ic cd builtin command. .It Xo +.Ic command +.Op Fl p +.Oo +.Ar utility +.Op Ar argument ... +.Oc +.Xc +Execute the specified +.Ar utility +as a simple command (see the +.Sx Simple Commands +section). +.Pp +If the +.Fl p +option is specified, the command search is performed using a +default value of +.Ev PATH +that is guaranteed to find all of the standard utilities. +.It Xo .Ic echo .Op Fl e | Fl n .Op Ar string