📄 shell.c
字号:
e = errno; /* If it's not in the current directory, try looking through PATH for it. */ path_filename = find_path_file (script_name); if (path_filename) { free (filename); filename = path_filename; fd = open (filename, O_RDONLY); } else errno = e; } if (fd < 0) { e = errno; file_error (filename); exit ((e == ENOENT) ? EX_NOTFOUND : EX_NOINPUT); } free (dollar_vars[0]); dollar_vars[0] = exec_argv0 ? savestring (exec_argv0) : savestring (script_name); if (exec_argv0) { free (exec_argv0); exec_argv0 = (char *)NULL; }#if defined (ARRAY_VARS) GET_ARRAY_FROM_VAR ("FUNCNAME", funcname_v, funcname_a); GET_ARRAY_FROM_VAR ("BASH_SOURCE", bash_source_v, bash_source_a); GET_ARRAY_FROM_VAR ("BASH_LINENO", bash_lineno_v, bash_lineno_a); array_push (bash_source_a, filename); if (bash_lineno_a) { t = itos (executing_line_number ()); array_push (bash_lineno_a, t); free (t); } array_push (funcname_a, "main");#endif#ifdef HAVE_DEV_FD fd_is_tty = isatty (fd);#else fd_is_tty = 0;#endif /* Only do this with non-tty file descriptors we can seek on. */ if (fd_is_tty == 0 && (lseek (fd, 0L, 1) != -1)) { /* Check to see if the `file' in `bash file' is a binary file according to the same tests done by execute_simple_command (), and report an error and exit if it is. */ sample_len = read (fd, sample, sizeof (sample)); if (sample_len < 0) { e = errno; if ((fstat (fd, &sb) == 0) && S_ISDIR (sb.st_mode)) internal_error (_("%s: is a directory"), filename); else { errno = e; file_error (filename); } exit (EX_NOEXEC); } else if (sample_len > 0 && (check_binary_file (sample, sample_len))) { internal_error (_("%s: cannot execute binary file"), filename); exit (EX_BINARY_FILE); } /* Now rewind the file back to the beginning. */ lseek (fd, 0L, 0); } /* Open the script. But try to move the file descriptor to a randomly large one, in the hopes that any descriptors used by the script will not match with ours. */ fd = move_to_high_fd (fd, 1, -1);#if defined (BUFFERED_INPUT) default_buffered_input = fd; SET_CLOSE_ON_EXEC (default_buffered_input);#else /* !BUFFERED_INPUT */ default_input = fdopen (fd, "r"); if (default_input == 0) { file_error (filename); exit (EX_NOTFOUND); } SET_CLOSE_ON_EXEC (fd); if (fileno (default_input) != fd) SET_CLOSE_ON_EXEC (fileno (default_input));#endif /* !BUFFERED_INPUT */ /* Just about the only way for this code to be executed is if something like `bash -i /dev/stdin' is executed. */ if (interactive_shell && fd_is_tty) { dup2 (fd, 0); close (fd); fd = 0;#if defined (BUFFERED_INPUT) default_buffered_input = 0;#else fclose (default_input); default_input = stdin;#endif } else if (forced_interactive && fd_is_tty == 0) /* But if a script is called with something like `bash -i scriptname', we need to do a non-interactive setup here, since we didn't do it before. */ init_interactive_script (); free (filename); return (fd);}/* Initialize the input routines for the parser. */static voidset_bash_input (){ /* Make sure the fd from which we are reading input is not in no-delay mode. */#if defined (BUFFERED_INPUT) if (interactive == 0) sh_unset_nodelay_mode (default_buffered_input); else#endif /* !BUFFERED_INPUT */ sh_unset_nodelay_mode (fileno (stdin)); /* with_input_from_stdin really means `with_input_from_readline' */ if (interactive && no_line_editing == 0) with_input_from_stdin ();#if defined (BUFFERED_INPUT) else if (interactive == 0) with_input_from_buffered_stream (default_buffered_input, dollar_vars[0]);#endif /* BUFFERED_INPUT */ else with_input_from_stream (default_input, dollar_vars[0]);}/* Close the current shell script input source and forget about it. This is extern so execute_cmd.c:initialize_subshell() can call it. If CHECK_ZERO is non-zero, we close default_buffered_input even if it's the standard input (fd 0). */voidunset_bash_input (check_zero) int check_zero;{#if defined (BUFFERED_INPUT) if ((check_zero && default_buffered_input >= 0) || (check_zero == 0 && default_buffered_input > 0)) { close_buffered_fd (default_buffered_input); default_buffered_input = bash_input.location.buffered_fd = -1; bash_input.type = st_none; /* XXX */ }#else /* !BUFFERED_INPUT */ if (default_input) { fclose (default_input); default_input = (FILE *)NULL; }#endif /* !BUFFERED_INPUT */} #if !defined (PROGRAM)# define PROGRAM "bash"#endifstatic voidset_shell_name (argv0) char *argv0;{ /* Here's a hack. If the name of this shell is "sh", then don't do any startup files; just try to be more like /bin/sh. */ shell_name = argv0 ? base_pathname (argv0) : PROGRAM; if (argv0 && *argv0 == '-') { if (*shell_name == '-') shell_name++; login_shell++; } if (shell_name[0] == 's' && shell_name[1] == 'h' && shell_name[2] == '\0') act_like_sh++; if (shell_name[0] == 's' && shell_name[1] == 'u' && shell_name[2] == '\0') su_shell++; shell_name = argv0 ? argv0 : PROGRAM; FREE (dollar_vars[0]); dollar_vars[0] = savestring (shell_name); /* A program may start an interactive shell with "execl ("/bin/bash", "-", NULL)". If so, default the name of this shell to our name. */ if (!shell_name || !*shell_name || (shell_name[0] == '-' && !shell_name[1])) shell_name = PROGRAM;}static voidinit_interactive (){ expand_aliases = interactive_shell = startup_state = 1; interactive = 1;}static voidinit_noninteractive (){#if defined (HISTORY) bash_history_reinit (0);#endif /* HISTORY */ interactive_shell = startup_state = interactive = 0; expand_aliases = posixly_correct; /* XXX - was 0 not posixly_correct */ no_line_editing = 1;#if defined (JOB_CONTROL) set_job_control (0);#endif /* JOB_CONTROL */}static voidinit_interactive_script (){ init_noninteractive (); expand_aliases = interactive_shell = startup_state = 1;}voidget_current_user_info (){ struct passwd *entry; /* Don't fetch this more than once. */ if (current_user.user_name == 0) { entry = getpwuid (current_user.uid); if (entry) { current_user.user_name = savestring (entry->pw_name); current_user.shell = (entry->pw_shell && entry->pw_shell[0]) ? savestring (entry->pw_shell) : savestring ("/bin/sh"); current_user.home_dir = savestring (entry->pw_dir); } else { current_user.user_name = _("I have no name!"); current_user.user_name = savestring (current_user.user_name); current_user.shell = savestring ("/bin/sh"); current_user.home_dir = savestring ("/"); } endpwent (); }}/* Do whatever is necessary to initialize the shell. Put new initializations in here. */static voidshell_initialize (){ char hostname[256]; /* Line buffer output for stderr and stdout. */ if (shell_initialized == 0) { sh_setlinebuf (stderr); sh_setlinebuf (stdout); } /* Sort the array of shell builtins so that the binary search in find_shell_builtin () works correctly. */ initialize_shell_builtins (); /* Initialize the trap signal handlers before installing our own signal handlers. traps.c:restore_original_signals () is responsible for restoring the original default signal handlers. That function is called when we make a new child. */ initialize_traps (); initialize_signals (0); /* It's highly unlikely that this will change. */ if (current_host_name == 0) { /* Initialize current_host_name. */ if (gethostname (hostname, 255) < 0) current_host_name = "??host??"; else current_host_name = savestring (hostname); } /* Initialize the stuff in current_user that comes from the password file. We don't need to do this right away if the shell is not interactive. */ if (interactive_shell) get_current_user_info (); /* Initialize our interface to the tilde expander. */ tilde_initialize (); /* Initialize internal and environment variables. Don't import shell functions from the environment if we are running in privileged or restricted mode or if the shell is running setuid. */#if defined (RESTRICTED_SHELL) initialize_shell_variables (shell_environment, privileged_mode||restricted||running_setuid);#else initialize_shell_variables (shell_environment, privileged_mode||running_setuid);#endif /* Initialize the data structures for storing and running jobs. */ initialize_job_control (0); /* Initialize input streams to null. */ initialize_bash_input (); initialize_flags (); /* Initialize the shell options. Don't import the shell options from the environment variables $SHELLOPTS or $BASHOPTS if we are running in privileged or restricted mode or if the shell is running setuid. */#if defined (RESTRICTED_SHELL) initialize_shell_options (privileged_mode||restricted||running_setuid); initialize_bashopts (privileged_mode||restricted||running_setuid);#else initialize_shell_options (privileged_mode||running_setuid); initialize_bashopts (privileged_mode||running_setuid);#endif}/* Function called by main () when it appears that the shell has already had some initialization performed. This is supposed to reset the world back to a pristine state, as if we had been exec'ed. */static voidshell_reinitialize (){ /* The default shell prompts. */ primary_prompt = PPROMPT; secondary_prompt = SPROMPT; /* Things that get 1. */ current_command_number = 1; /* We have decided that the ~/.bashrc file should not be executed for the invocation of each shell script. If the variable $ENV (or $BASH_ENV) is set, its value is used as the name of a file to source. */ no_rc = no_profile = 1; /* Things that get 0. */ login_shell = make_login_shell = interactive = executing = 0; debugging = do_version = line_number = last_command_exit_value = 0; forced_interactive = interactive_shell = subshell_environment = 0; expand_aliases = 0;#if defined (HISTORY) bash_history_reinit (0);#endif /* HISTORY */#if defined (RESTRICTED_SHELL) restricted = 0;#endif /* RESTRICTED_SHELL */ /* Ensure that the default startup file is used. (Except that we don't execute this file for reinitialized shells). */ bashrc_file = "~/.bashrc"; /* Delete all variables and functions. They will be reinitialized when the environment is parsed. */ delete_all_contexts (shell_variables); delete_all_variables (shell_functions); reinit_special_variables ();#if defined (READLINE) bashline_reinitialize ();#endif shell_reinitialized = 1;}static voidshow_shell_usage (fp, extra) FILE *fp; int extra;{ int i; char *set_opts, *s, *t; if (extra) fprintf (fp, _("GNU bash, version %s-(%s)\n"), shell_version_string (), MACHTYPE); fprintf (fp, _("Usage:\t%s [GNU long option] [option] ...\n\t%s [GNU long option] [option] script-file ...\n"), shell_name, shell_name); fputs (_("GNU long options:\n"), fp); for (i = 0; long_args[i].name; i++) fprintf (fp, "\t--%s\n", long_args[i].name); fputs (_("Shell options:\n"), fp); fputs (_("\t-irsD or -c command or -O shopt_option\t\t(invocation only)\n"), fp); for (i = 0, set_opts = 0; shell_builtins[i].name; i++) if (STREQ (shell_builtins[i].name, "set")) set_opts = savestring (shell_builtins[i].short_doc); if (set_opts) { s = strchr (set_opts, '['); if (s == 0) s = set_opts; while (*++s == '-') ; t = strchr (s, ']'); if (t) *t = '\0'; fprintf (fp, _("\t-%s or -o option\n"), s); free (set_opts); } if (extra) { fprintf (fp, _("Type `%s -c \"help set\"' for more information about shell options.\n"), shell_name); fprintf (fp, _("Type `%s -c help' for more information about shell builtin commands.\n"), shell_name); fprintf (fp, _("Use the `bashbug' command to report bugs.\n")); }}static voidadd_shopt_to_alist (opt, on_or_off) char *opt; int on_or_off;{ if (shopt_ind >= shopt_len) { shopt_len += 8; shopt_alist = (STRING_INT_ALIST *)xrealloc (shopt_alist, shopt_len * sizeof (shopt_alist[0])); } shopt_alist[shopt_ind].word = opt; shopt_alist[shopt_ind].token = on_or_off; shopt_ind++;}static voidrun_shopt_alist (){ register int i; for (i = 0; i < shopt_ind; i++) if (shopt_setopt (shopt_alist[i].word, (shopt_alist[i].token == '-')) != EXECUTION_SUCCESS) exit (EX_BADUSAGE); free (shopt_alist); shopt_alist = 0; shopt_ind = shopt_len = 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -