📄 shell.c
字号:
exit (EXECUTION_SUCCESS); } /* All done with full word options; do standard shell option parsing.*/ this_command_name = shell_name; /* for error reporting */ arg_index = parse_shell_options (argv, arg_index, argc); /* If user supplied the "--login" (or -l) flag, then set and invert LOGIN_SHELL. */ if (make_login_shell) { login_shell++; login_shell = -login_shell; } set_login_shell ("login_shell", login_shell != 0); if (dump_po_strings) dump_translatable_strings = 1; if (dump_translatable_strings) read_but_dont_execute = 1; if (running_setuid && privileged_mode == 0) disable_priv_mode (); /* Need to get the argument to a -c option processed in the above loop. The next arg is a command to execute, and the following args are $0...$n respectively. */ if (want_pending_command) { command_execution_string = argv[arg_index]; if (command_execution_string == 0) { report_error (_("%s: option requires an argument"), "-c"); exit (EX_BADUSAGE); } arg_index++; } this_command_name = (char *)NULL; cmd_init(); /* initialize the command object caches */ /* First, let the outside world know about our interactive status. A shell is interactive if the `-i' flag was given, or if all of the following conditions are met: no -c command no arguments remaining or the -s flag given standard input is a terminal standard error is a terminal Refer to Posix.2, the description of the `sh' utility. */ if (forced_interactive || /* -i flag */ (!command_execution_string && /* No -c command and ... */ wordexp_only == 0 && /* No --wordexp and ... */ ((arg_index == argc) || /* no remaining args or... */ read_from_stdin) && /* -s flag with args, and */ isatty (fileno (stdin)) && /* Input is a terminal and */ isatty (fileno (stderr)))) /* error output is a terminal. */ init_interactive (); else init_noninteractive (); /* * Some systems have the bad habit of starting login shells with lots of open * file descriptors. For instance, most systems that have picked up the * pre-4.0 Sun YP code leave a file descriptor open each time you call one * of the getpw* functions, and it's set to be open across execs. That * means one for login, one for xterm, one for shelltool, etc. There are * also systems that open persistent FDs to other agents or files as part * of process startup; these need to be set to be close-on-exec. */ if (login_shell && interactive_shell) { for (i = 3; i < 20; i++) SET_CLOSE_ON_EXEC (i); } /* If we're in a strict Posix.2 mode, turn on interactive comments, alias expansion in non-interactive shells, and other Posix.2 things. */ if (posixly_correct) { bind_variable ("POSIXLY_CORRECT", "y", 0); sv_strict_posix ("POSIXLY_CORRECT"); } /* Now we run the shopt_alist and process the options. */ if (shopt_alist) run_shopt_alist (); /* From here on in, the shell must be a normal functioning shell. Variables from the environment are expected to be set, etc. */ shell_initialize (); set_default_lang (); set_default_locale_vars (); /* * M-x term -> TERM=eterm EMACS=22.1 (term:0.96) (eterm) * M-x shell -> TERM=dumb EMACS=t (no line editing) * M-x terminal -> TERM=emacs-em7955 EMACS= (line editing) */ if (interactive_shell) { char *term, *emacs; term = get_string_value ("TERM"); emacs = get_string_value ("EMACS"); /* Not sure any emacs terminal emulator sets TERM=emacs any more */ no_line_editing |= term && (STREQ (term, "emacs")); no_line_editing |= emacs && emacs[0] == 't' && emacs[1] == '\0' && STREQ (term, "dumb"); /* running_under_emacs == 2 for `eterm' */ running_under_emacs = (emacs != 0) || (term && STREQN (term, "emacs", 5)); running_under_emacs += term && STREQN (term, "eterm", 5) && emacs && strstr (emacs, "term"); if (running_under_emacs) gnu_error_format = 1; } top_level_arg_index = arg_index; old_errexit_flag = exit_immediately_on_error; /* Give this shell a place to longjmp to before executing the startup files. This allows users to press C-c to abort the lengthy startup. */ code = setjmp (top_level); if (code) { if (code == EXITPROG || code == ERREXIT) exit_shell (last_command_exit_value); else {#if defined (JOB_CONTROL) /* Reset job control, since run_startup_files turned it off. */ set_job_control (interactive_shell);#endif /* Reset value of `set -e', since it's turned off before running the startup files. */ exit_immediately_on_error += old_errexit_flag; locally_skip_execution++; } } arg_index = top_level_arg_index; /* Execute the start-up scripts. */ if (interactive_shell == 0) { unbind_variable ("PS1"); unbind_variable ("PS2"); interactive = 0;#if 0 /* This has already been done by init_noninteractive */ expand_aliases = posixly_correct;#endif } else { change_flag ('i', FLAG_ON); interactive = 1; }#if defined (RESTRICTED_SHELL) /* Set restricted_shell based on whether the basename of $0 indicates that the shell should be restricted or if the `-r' option was supplied at startup. */ restricted_shell = shell_is_restricted (shell_name); /* If the `-r' option is supplied at invocation, make sure that the shell is not in restricted mode when running the startup files. */ saverst = restricted; restricted = 0;#endif /* The startup files are run with `set -e' temporarily disabled. */ if (locally_skip_execution == 0 && running_setuid == 0) { old_errexit_flag = exit_immediately_on_error; exit_immediately_on_error = 0; run_startup_files (); exit_immediately_on_error += old_errexit_flag; } /* If we are invoked as `sh', turn on Posix mode. */ if (act_like_sh) { bind_variable ("POSIXLY_CORRECT", "y", 0); sv_strict_posix ("POSIXLY_CORRECT"); }#if defined (RESTRICTED_SHELL) /* Turn on the restrictions after executing the startup files. This means that `bash -r' or `set -r' invoked from a startup file will turn on the restrictions after the startup files are executed. */ restricted = saverst || restricted; if (shell_reinitialized == 0) maybe_make_restricted (shell_name);#endif /* RESTRICTED_SHELL */#if defined (WORDEXP_OPTION) if (wordexp_only) { startup_state = 3; last_command_exit_value = run_wordexp (argv[arg_index]); exit_shell (last_command_exit_value); }#endif if (command_execution_string) { arg_index = bind_args (argv, arg_index, argc, 0); startup_state = 2; if (debugging_mode) start_debugger ();#if defined (ONESHOT) executing = 1; run_one_command (command_execution_string); exit_shell (last_command_exit_value);#else /* ONESHOT */ with_input_from_string (command_execution_string, "-c"); goto read_and_execute;#endif /* !ONESHOT */ } /* Get possible input filename and set up default_buffered_input or default_input as appropriate. */ if (arg_index != argc && read_from_stdin == 0) { open_shell_script (argv[arg_index]); arg_index++; } else if (interactive == 0) /* In this mode, bash is reading a script from stdin, which is a pipe or redirected file. */#if defined (BUFFERED_INPUT) default_buffered_input = fileno (stdin); /* == 0 */#else setbuf (default_input, (char *)NULL);#endif /* !BUFFERED_INPUT */ set_bash_input (); /* Bind remaining args to $1 ... $n */ arg_index = bind_args (argv, arg_index, argc, 1); if (debugging_mode && locally_skip_execution == 0 && running_setuid == 0) start_debugger (); /* Do the things that should be done only for interactive shells. */ if (interactive_shell) { /* Set up for checking for presence of mail. */ reset_mail_timer (); init_mail_dates ();#if defined (HISTORY) /* Initialize the interactive history stuff. */ bash_initialize_history (); /* Don't load the history from the history file if we've already saved some lines in this session (e.g., by putting `history -s xx' into one of the startup files). */ if (shell_initialized == 0 && history_lines_this_session == 0) load_history ();#endif /* HISTORY */ /* Initialize terminal state for interactive shells after the .bash_profile and .bashrc are interpreted. */ get_tty_state (); }#if !defined (ONESHOT) read_and_execute:#endif /* !ONESHOT */ shell_initialized = 1; /* Read commands until exit condition. */ reader_loop (); exit_shell (last_command_exit_value);}static intparse_long_options (argv, arg_start, arg_end) char **argv; int arg_start, arg_end;{ int arg_index, longarg, i; char *arg_string; arg_index = arg_start; while ((arg_index != arg_end) && (arg_string = argv[arg_index]) && (*arg_string == '-')) { longarg = 0; /* Make --login equivalent to -login. */ if (arg_string[1] == '-' && arg_string[2]) { longarg = 1; arg_string++; } for (i = 0; long_args[i].name; i++) { if (STREQ (arg_string + 1, long_args[i].name)) { if (long_args[i].type == Int) *long_args[i].int_value = 1; else if (argv[++arg_index] == 0) { report_error (_("%s: option requires an argument"), long_args[i].name); exit (EX_BADUSAGE); } else *long_args[i].char_value = argv[arg_index]; break; } } if (long_args[i].name == 0) { if (longarg) { report_error (_("%s: invalid option"), argv[arg_index]); show_shell_usage (stderr, 0); exit (EX_BADUSAGE); } break; /* No such argument. Maybe flag arg. */ } arg_index++; } return (arg_index);}static intparse_shell_options (argv, arg_start, arg_end) char **argv; int arg_start, arg_end;{ int arg_index; int arg_character, on_or_off, next_arg, i; char *o_option, *arg_string; arg_index = arg_start; while (arg_index != arg_end && (arg_string = argv[arg_index]) && (*arg_string == '-' || *arg_string == '+')) { /* There are flag arguments, so parse them. */ next_arg = arg_index + 1; /* A single `-' signals the end of options. From the 4.3 BSD sh. An option `--' means the same thing; this is the standard getopt(3) meaning. */ if (arg_string[0] == '-' && (arg_string[1] == '\0' || (arg_string[1] == '-' && arg_string[2] == '\0'))) return (next_arg); i = 1; on_or_off = arg_string[0]; while (arg_character = arg_string[i++]) { switch (arg_character) { case 'c': want_pending_command = 1; break; case 'l': make_login_shell = 1; break; case 's': read_from_stdin = 1; break; case 'o': o_option = argv[next_arg]; if (o_option == 0) { list_minus_o_opts (-1, (on_or_off == '-') ? 0 : 1); break; } if (set_minus_o_option (on_or_off, o_option) != EXECUTION_SUCCESS) exit (EX_BADUSAGE); next_arg++; break; case 'O': /* Since some of these can be overridden by the normal interactive/non-interactive shell initialization or initializing posix mode, we save the options and process them after initialization. */ o_option = argv[next_arg]; if (o_option == 0) { shopt_listopt (o_option, (on_or_off == '-') ? 0 : 1); break; } add_shopt_to_alist (o_option, on_or_off); next_arg++; break; case 'D': dump_translatable_strings = 1; break; default: if (change_flag (arg_character, on_or_off) == FLAG_ERROR) { report_error (_("%c%c: invalid option"), on_or_off, arg_character); show_shell_usage (stderr, 0); exit (EX_BADUSAGE); } } } /* Can't do just a simple increment anymore -- what about "bash -abouo emacs ignoreeof -hP"? */ arg_index = next_arg; } return (arg_index);}/* Exit the shell with status S. */voidexit_shell (s) int s;{ fflush (stdout); /* XXX */ fflush (stderr); /* Do trap[0] if defined. Allow it to override the exit status passed to us. */ if (signal_is_trapped (0)) s = run_exit_trap ();#if defined (PROCESS_SUBSTITUTION) unlink_fifo_list ();#endif /* PROCESS_SUBSTITUTION */#if defined (HISTORY) if (interactive_shell) maybe_save_shell_history ();#endif /* HISTORY */#if defined (COPROCESS_SUPPORT) coproc_flush ();#endif#if defined (JOB_CONTROL) /* If the user has run `shopt -s huponexit', hangup all jobs when we exit an interactive login shell. ksh does this unconditionally. */ if (interactive_shell && login_shell && hup_on_exit) hangup_all_jobs (); /* If this shell is interactive, terminate all stopped jobs and
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -