📄 execute_cmd.c
字号:
break;#endif case cm_function_def: exec_result = execute_intern_function (command->value.Function_def->name, command->value.Function_def->command); break; default: command_error ("execute_command", CMDERR_BADTYPE, command->type, 0); } if (my_undo_list) { do_redirections (my_undo_list, RX_ACTIVE); dispose_redirects (my_undo_list); } if (exec_undo_list) dispose_redirects (exec_undo_list); if (my_undo_list || exec_undo_list) discard_unwind_frame ("loop_redirections"); /* Invert the return value if we have to */ if (invert) exec_result = (exec_result == EXECUTION_SUCCESS) ? EXECUTION_FAILURE : EXECUTION_SUCCESS;#if defined (DPAREN_ARITHMETIC) || defined (COND_COMMAND) /* This is where we set PIPESTATUS from the exit status of the appropriate compound commands (the ones that look enough like simple commands to cause confusion). We might be able to optimize by not doing this if subshell_environment != 0. */ switch (command->type) {# if defined (DPAREN_ARITHMETIC) case cm_arith:# endif# if defined (COND_COMMAND) case cm_cond:# endif set_pipestatus_from_exit (exec_result); break; }#endif last_command_exit_value = exec_result; run_pending_traps ();#if 0 if (running_trap == 0)#endif currently_executing_command = (COMMAND *)NULL; return (last_command_exit_value);}#if defined (COMMAND_TIMING)#if defined (HAVE_GETRUSAGE) && defined (HAVE_GETTIMEOFDAY)extern struct timeval *difftimeval __P((struct timeval *, struct timeval *, struct timeval *));extern struct timeval *addtimeval __P((struct timeval *, struct timeval *, struct timeval *));extern int timeval_to_cpu __P((struct timeval *, struct timeval *, struct timeval *));#endif#define POSIX_TIMEFORMAT "real %2R\nuser %2U\nsys %2S"#define BASH_TIMEFORMAT "\nreal\t%3lR\nuser\t%3lU\nsys\t%3lS"static const int precs[] = { 0, 100, 10, 1 };/* Expand one `%'-prefixed escape sequence from a time format string. */static intmkfmt (buf, prec, lng, sec, sec_fraction) char *buf; int prec, lng; time_t sec; int sec_fraction;{ time_t min; char abuf[INT_STRLEN_BOUND(time_t) + 1]; int ind, aind; ind = 0; abuf[sizeof(abuf) - 1] = '\0'; /* If LNG is non-zero, we want to decompose SEC into minutes and seconds. */ if (lng) { min = sec / 60; sec %= 60; aind = sizeof(abuf) - 2; do abuf[aind--] = (min % 10) + '0'; while (min /= 10); aind++; while (abuf[aind]) buf[ind++] = abuf[aind++]; buf[ind++] = 'm'; } /* Now add the seconds. */ aind = sizeof (abuf) - 2; do abuf[aind--] = (sec % 10) + '0'; while (sec /= 10); aind++; while (abuf[aind]) buf[ind++] = abuf[aind++]; /* We want to add a decimal point and PREC places after it if PREC is nonzero. PREC is not greater than 3. SEC_FRACTION is between 0 and 999. */ if (prec != 0) { buf[ind++] = '.'; for (aind = 1; aind <= prec; aind++) { buf[ind++] = (sec_fraction / precs[aind]) + '0'; sec_fraction %= precs[aind]; } } if (lng) buf[ind++] = 's'; buf[ind] = '\0'; return (ind);}/* Interpret the format string FORMAT, interpolating the following escape sequences: %[prec][l][RUS] where the optional `prec' is a precision, meaning the number of characters after the decimal point, the optional `l' means to format using minutes and seconds (MMmNN[.FF]s), like the `times' builtin', and the last character is one of R number of seconds of `real' time U number of seconds of `user' time S number of seconds of `system' time An occurrence of `%%' in the format string is translated to a `%'. The result is printed to FP, a pointer to a FILE. The other variables are the seconds and thousandths of a second of real, user, and system time, resectively. */static voidprint_formatted_time (fp, format, rs, rsf, us, usf, ss, ssf, cpu) FILE *fp; char *format; time_t rs; int rsf; time_t us; int usf; time_t ss; int ssf, cpu;{ int prec, lng, len; char *str, *s, ts[INT_STRLEN_BOUND (time_t) + sizeof ("mSS.FFFF")]; time_t sum; int sum_frac; int sindex, ssize; len = strlen (format); ssize = (len + 64) - (len % 64); str = (char *)xmalloc (ssize); sindex = 0; for (s = format; *s; s++) { if (*s != '%' || s[1] == '\0') { RESIZE_MALLOCED_BUFFER (str, sindex, 1, ssize, 64); str[sindex++] = *s; } else if (s[1] == '%') { s++; RESIZE_MALLOCED_BUFFER (str, sindex, 1, ssize, 64); str[sindex++] = *s; } else if (s[1] == 'P') { s++;#if 0 /* clamp CPU usage at 100% */ if (cpu > 10000) cpu = 10000;#endif sum = cpu / 100; sum_frac = (cpu % 100) * 10; len = mkfmt (ts, 2, 0, sum, sum_frac); RESIZE_MALLOCED_BUFFER (str, sindex, len, ssize, 64); strcpy (str + sindex, ts); sindex += len; } else { prec = 3; /* default is three places past the decimal point. */ lng = 0; /* default is to not use minutes or append `s' */ s++; if (DIGIT (*s)) /* `precision' */ { prec = *s++ - '0'; if (prec > 3) prec = 3; } if (*s == 'l') /* `length extender' */ { lng = 1; s++; } if (*s == 'R' || *s == 'E') len = mkfmt (ts, prec, lng, rs, rsf); else if (*s == 'U') len = mkfmt (ts, prec, lng, us, usf); else if (*s == 'S') len = mkfmt (ts, prec, lng, ss, ssf); else { internal_error (_("TIMEFORMAT: `%c': invalid format character"), *s); free (str); return; } RESIZE_MALLOCED_BUFFER (str, sindex, len, ssize, 64); strcpy (str + sindex, ts); sindex += len; } } str[sindex] = '\0'; fprintf (fp, "%s\n", str); fflush (fp); free (str);}static inttime_command (command, asynchronous, pipe_in, pipe_out, fds_to_close) COMMAND *command; int asynchronous, pipe_in, pipe_out; struct fd_bitmap *fds_to_close;{ int rv, posix_time, old_flags, nullcmd; time_t rs, us, ss; int rsf, usf, ssf; int cpu; char *time_format;#if defined (HAVE_GETRUSAGE) && defined (HAVE_GETTIMEOFDAY) struct timeval real, user, sys; struct timeval before, after;# if defined (HAVE_STRUCT_TIMEZONE) struct timezone dtz; /* posix doesn't define this */# endif struct rusage selfb, selfa, kidsb, kidsa; /* a = after, b = before */#else# if defined (HAVE_TIMES) clock_t tbefore, tafter, real, user, sys; struct tms before, after;# endif#endif#if defined (HAVE_GETRUSAGE) && defined (HAVE_GETTIMEOFDAY)# if defined (HAVE_STRUCT_TIMEZONE) gettimeofday (&before, &dtz);# else gettimeofday (&before, (void *)NULL);# endif /* !HAVE_STRUCT_TIMEZONE */ getrusage (RUSAGE_SELF, &selfb); getrusage (RUSAGE_CHILDREN, &kidsb);#else# if defined (HAVE_TIMES) tbefore = times (&before);# endif#endif posix_time = (command->flags & CMD_TIME_POSIX); nullcmd = (command == 0) || (command->type == cm_simple && command->value.Simple->words == 0 && command->value.Simple->redirects == 0); if (posixly_correct && nullcmd) {#if defined (HAVE_GETRUSAGE) selfb.ru_utime.tv_sec = kidsb.ru_utime.tv_sec = selfb.ru_stime.tv_sec = kidsb.ru_stime.tv_sec = 0; selfb.ru_utime.tv_usec = kidsb.ru_utime.tv_usec = selfb.ru_stime.tv_usec = kidsb.ru_stime.tv_usec = 0; before.tv_sec = shell_start_time; before.tv_usec = 0;#else before.tms_utime = before.tms_stime = before.tms_cutime = before.tms_cstime = 0; tbefore = shell_start_time;#endif } old_flags = command->flags; command->flags &= ~(CMD_TIME_PIPELINE|CMD_TIME_POSIX); rv = execute_command_internal (command, asynchronous, pipe_in, pipe_out, fds_to_close); command->flags = old_flags; rs = us = ss = 0; rsf = usf = ssf = cpu = 0;#if defined (HAVE_GETRUSAGE) && defined (HAVE_GETTIMEOFDAY)# if defined (HAVE_STRUCT_TIMEZONE) gettimeofday (&after, &dtz);# else gettimeofday (&after, (void *)NULL);# endif /* !HAVE_STRUCT_TIMEZONE */ getrusage (RUSAGE_SELF, &selfa); getrusage (RUSAGE_CHILDREN, &kidsa); difftimeval (&real, &before, &after); timeval_to_secs (&real, &rs, &rsf); addtimeval (&user, difftimeval(&after, &selfb.ru_utime, &selfa.ru_utime), difftimeval(&before, &kidsb.ru_utime, &kidsa.ru_utime)); timeval_to_secs (&user, &us, &usf); addtimeval (&sys, difftimeval(&after, &selfb.ru_stime, &selfa.ru_stime), difftimeval(&before, &kidsb.ru_stime, &kidsa.ru_stime)); timeval_to_secs (&sys, &ss, &ssf); cpu = timeval_to_cpu (&real, &user, &sys);#else# if defined (HAVE_TIMES) tafter = times (&after); real = tafter - tbefore; clock_t_to_secs (real, &rs, &rsf); user = (after.tms_utime - before.tms_utime) + (after.tms_cutime - before.tms_cutime); clock_t_to_secs (user, &us, &usf); sys = (after.tms_stime - before.tms_stime) + (after.tms_cstime - before.tms_cstime); clock_t_to_secs (sys, &ss, &ssf); cpu = (real == 0) ? 0 : ((user + sys) * 10000) / real;# else rs = us = ss = 0; rsf = usf = ssf = cpu = 0;# endif#endif if (posix_time) time_format = POSIX_TIMEFORMAT; else if ((time_format = get_string_value ("TIMEFORMAT")) == 0) { if (posixly_correct && nullcmd) time_format = "user\t%2lU\nsys\t%2lS"; else time_format = BASH_TIMEFORMAT; } if (time_format && *time_format) print_formatted_time (stderr, time_format, rs, rsf, us, usf, ss, ssf, cpu); return rv;}#endif /* COMMAND_TIMING *//* Execute a command that's supposed to be in a subshell. This must be called after make_child and we must be running in the child process. The caller will return or exit() immediately with the value this returns. */static intexecute_in_subshell (command, asynchronous, pipe_in, pipe_out, fds_to_close) COMMAND *command; int asynchronous; int pipe_in, pipe_out; struct fd_bitmap *fds_to_close;{ int user_subshell, return_code, function_value, should_redir_stdin, invert; int ois, user_coproc; int result; volatile COMMAND *tcom; USE_VAR(user_subshell); USE_VAR(user_coproc); USE_VAR(invert); USE_VAR(tcom); USE_VAR(asynchronous); subshell_level++; should_redir_stdin = (asynchronous && (command->flags & CMD_STDIN_REDIR) && pipe_in == NO_PIPE && stdin_redirects (command->redirects) == 0); invert = (command->flags & CMD_INVERT_RETURN) != 0; user_subshell = command->type == cm_subshell || ((command->flags & CMD_WANT_SUBSHELL) != 0); user_coproc = command->type == cm_coproc; command->flags &= ~(CMD_FORCE_SUBSHELL | CMD_WANT_SUBSHELL | CMD_INVERT_RETURN); /* If a command is asynchronous in a subshell (like ( foo ) & or the special case of an asynchronous GROUP command where the the subshell bit is turned on down in case cm_group: below), turn off `asynchronous', so that two subshells aren't spawned. XXX - asynchronous used to be set to 0 in this block, but that means that setup_async_signals was never run. Now it's set to 0 after subshell_environment is set appropriately and setup_async_signals is run. This seems semantically correct to me. For example, ( foo ) & seems to say ``do the command `foo' in a subshell environment, but don't wait for that subshell to finish'', and "{ foo ; bar ; } &" seems to me to be like functions or builtins in the background, which executed in a subshell environment. I just don't see the need to fork two subshells. */ /* Don't fork again, we are already in a subshell. A `doubly async' shell is not interactive, however. */ if (asynchronous) {#if defined (JOB_CONTROL) /* If a construct like ( exec xxx yyy ) & is given while job control is active, we want to prevent exec from putting the subshell back into the original process group, carefully undoing all the work we just did in make_child. */ original_pgrp = -1;#endif /* JOB_CONTROL */ ois = interactive_shell; interactive_shell = 0; /* This test is to prevent alias expansion by interactive shells that run `(command) &' but to allow scripts that have enabled alias expansion with `shopt -s expand_alias' to continue to expand aliases. */ if (ois != interactive_shell) expand_aliases = 0; } /* Subshells are neither login nor interactive. */ login_shell = interactive = 0; if (user_subshell) subshell_environment = SUBSHELL_PAREN; else { subshell_environment = 0; /* XXX */ if (asynchronous) subshell_environment |= SUBSHELL_ASYNC; if (pipe_in != NO_PIPE || pipe_out != NO_PIPE) subshell_environment |= SUBSHELL_PIPE; if (user_coproc) subshell_environment |= SUBSHELL_COPROC; } reset_terminating_signals (); /* in sig.c */ /* Cancel traps, in trap.c. */ /* Reset the signal handlers in the child, but don't free the trap strings. Set a flag noting that we have to free the trap strings if we run trap to change a signal disposition. */ reset_signal_handlers (); subshell_environment |= SUBSHELL_RESETTRAP; /* Make sure restore_original_signals doesn't undo the work done by make_child to ensure that asynchronous children are immune to SIGINT and SIGQUIT. Turn off asynchronous to make sure more subshells are not spawned. */ if (asynchronous) { setup_async_signals (); asynchronous = 0; }#if defined (JOB_CONTROL) set_sigchld_handler ();#endif /* JOB_CONTROL */ set_sigint_handler ();#if defined (JOB_CONTROL) /* Delete all traces that there were any jobs running. This is only for subshells. */ without_job_control ();#endif /* JOB_CONTROL */ if (fds_to_close)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -