📄 variables.c
字号:
/* variables.c -- Functions for hacking shell variables. *//* Copyright (C) 1987-2010 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. Bash is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Bash is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Bash. If not, see <http://www.gnu.org/licenses/>.*/#include "config.h"#include "bashtypes.h"#include "posixstat.h"#include "posixtime.h"#if defined (__QNX__)# if defined (__QNXNTO__)# include <sys/netmgr.h># else# include <sys/vc.h># endif /* !__QNXNTO__ */#endif /* __QNX__ */#if defined (HAVE_UNISTD_H)# include <unistd.h>#endif#include <stdio.h>#include "chartypes.h"#if defined (HAVE_PWD_H)# include <pwd.h>#endif#include "bashansi.h"#include "bashintl.h"#define NEED_XTRACE_SET_DECL#include "shell.h"#include "flags.h"#include "execute_cmd.h"#include "findcmd.h"#include "mailcheck.h"#include "input.h"#include "hashcmd.h"#include "pathexp.h"#include "alias.h"#include "builtins/getopt.h"#include "builtins/common.h"#if defined (READLINE)# include "bashline.h"# include <readline/readline.h>#else# include <tilde/tilde.h>#endif#if defined (HISTORY)# include "bashhist.h"# include <readline/history.h>#endif /* HISTORY */#if defined (PROGRAMMABLE_COMPLETION)# include "pcomplete.h"#endif#define TEMPENV_HASH_BUCKETS 4 /* must be power of two */#define ifsname(s) ((s)[0] == 'I' && (s)[1] == 'F' && (s)[2] == 'S' && (s)[3] == '\0')extern char **environ;/* Variables used here and defined in other files. */extern int posixly_correct;extern int line_number, line_number_base;extern int subshell_environment, indirection_level, subshell_level;extern int build_version, patch_level;extern int expanding_redir;extern char *dist_version, *release_status;extern char *shell_name;extern char *primary_prompt, *secondary_prompt;extern char *current_host_name;extern sh_builtin_func_t *this_shell_builtin;extern SHELL_VAR *this_shell_function;extern char *the_printed_command_except_trap;extern char *this_command_name;extern char *command_execution_string;extern time_t shell_start_time;extern int assigning_in_environment;extern int executing_builtin;extern int funcnest_max;#if defined (READLINE)extern int no_line_editing;extern int perform_hostname_completion;#endif/* The list of shell variables that the user has created at the global scope, or that came from the environment. */VAR_CONTEXT *global_variables = (VAR_CONTEXT *)NULL;/* The current list of shell variables, including function scopes */VAR_CONTEXT *shell_variables = (VAR_CONTEXT *)NULL;/* The list of shell functions that the user has created, or that came from the environment. */HASH_TABLE *shell_functions = (HASH_TABLE *)NULL;#if defined (DEBUGGER)/* The table of shell function definitions that the user defined or that came from the environment. */HASH_TABLE *shell_function_defs = (HASH_TABLE *)NULL;#endif/* The current variable context. This is really a count of how deep into executing functions we are. */int variable_context = 0;/* The set of shell assignments which are made only in the environment for a single command. */HASH_TABLE *temporary_env = (HASH_TABLE *)NULL;/* Set to non-zero if an assignment error occurs while putting variables into the temporary environment. */int tempenv_assign_error;/* Some funky variables which are known about specially. Here is where "$*", "$1", and all the cruft is kept. */char *dollar_vars[10];WORD_LIST *rest_of_args = (WORD_LIST *)NULL;/* The value of $$. */pid_t dollar_dollar_pid;/* Non-zero means that we have to remake EXPORT_ENV. */int array_needs_making = 1;/* The number of times BASH has been executed. This is set by initialize_variables (). */int shell_level = 0;/* An array which is passed to commands as their environment. It is manufactured from the union of the initial environment and the shell variables that are marked for export. */char **export_env = (char **)NULL;static int export_env_index;static int export_env_size;#if defined (READLINE)static int winsize_assignment; /* currently assigning to LINES or COLUMNS */#endif/* Some forward declarations. */static void create_variable_tables __P((void));static void set_machine_vars __P((void));static void set_home_var __P((void));static void set_shell_var __P((void));static char *get_bash_name __P((void));static void initialize_shell_level __P((void));static void uidset __P((void));#if defined (ARRAY_VARS)static void make_vers_array __P((void));#endifstatic SHELL_VAR *null_assign __P((SHELL_VAR *, char *, arrayind_t, char *));#if defined (ARRAY_VARS)static SHELL_VAR *null_array_assign __P((SHELL_VAR *, char *, arrayind_t, char *));#endifstatic SHELL_VAR *get_self __P((SHELL_VAR *));#if defined (ARRAY_VARS)static SHELL_VAR *init_dynamic_array_var __P((char *, sh_var_value_func_t *, sh_var_assign_func_t *, int));static SHELL_VAR *init_dynamic_assoc_var __P((char *, sh_var_value_func_t *, sh_var_assign_func_t *, int));#endifstatic SHELL_VAR *assign_seconds __P((SHELL_VAR *, char *, arrayind_t, char *));static SHELL_VAR *get_seconds __P((SHELL_VAR *));static SHELL_VAR *init_seconds_var __P((void));static int brand __P((void));static void sbrand __P((unsigned long)); /* set bash random number generator. */static void seedrand __P((void)); /* seed generator randomly */static SHELL_VAR *assign_random __P((SHELL_VAR *, char *, arrayind_t, char *));static SHELL_VAR *get_random __P((SHELL_VAR *));static SHELL_VAR *assign_lineno __P((SHELL_VAR *, char *, arrayind_t, char *));static SHELL_VAR *get_lineno __P((SHELL_VAR *));static SHELL_VAR *assign_subshell __P((SHELL_VAR *, char *, arrayind_t, char *));static SHELL_VAR *get_subshell __P((SHELL_VAR *));static SHELL_VAR *get_bashpid __P((SHELL_VAR *));#if defined (HISTORY)static SHELL_VAR *get_histcmd __P((SHELL_VAR *));#endif#if defined (READLINE)static SHELL_VAR *get_comp_wordbreaks __P((SHELL_VAR *));static SHELL_VAR *assign_comp_wordbreaks __P((SHELL_VAR *, char *, arrayind_t, char *));#endif#if defined (PUSHD_AND_POPD) && defined (ARRAY_VARS)static SHELL_VAR *assign_dirstack __P((SHELL_VAR *, char *, arrayind_t, char *));static SHELL_VAR *get_dirstack __P((SHELL_VAR *));#endif#if defined (ARRAY_VARS)static SHELL_VAR *get_groupset __P((SHELL_VAR *));static SHELL_VAR *build_hashcmd __P((SHELL_VAR *));static SHELL_VAR *get_hashcmd __P((SHELL_VAR *));static SHELL_VAR *assign_hashcmd __P((SHELL_VAR *, char *, arrayind_t, char *));# if defined (ALIAS)static SHELL_VAR *build_aliasvar __P((SHELL_VAR *));static SHELL_VAR *get_aliasvar __P((SHELL_VAR *));static SHELL_VAR *assign_aliasvar __P((SHELL_VAR *, char *, arrayind_t, char *));# endif#endifstatic SHELL_VAR *get_funcname __P((SHELL_VAR *));static SHELL_VAR *init_funcname_var __P((void));static void initialize_dynamic_variables __P((void));static SHELL_VAR *hash_lookup __P((const char *, HASH_TABLE *));static SHELL_VAR *new_shell_variable __P((const char *));static SHELL_VAR *make_new_variable __P((const char *, HASH_TABLE *));static SHELL_VAR *bind_variable_internal __P((const char *, char *, HASH_TABLE *, int, int));static void dispose_variable_value __P((SHELL_VAR *));static void free_variable_hash_data __P((PTR_T));static VARLIST *vlist_alloc __P((int));static VARLIST *vlist_realloc __P((VARLIST *, int));static void vlist_add __P((VARLIST *, SHELL_VAR *, int));static void flatten __P((HASH_TABLE *, sh_var_map_func_t *, VARLIST *, int));static int qsort_var_comp __P((SHELL_VAR **, SHELL_VAR **));static SHELL_VAR **vapply __P((sh_var_map_func_t *));static SHELL_VAR **fapply __P((sh_var_map_func_t *));static int visible_var __P((SHELL_VAR *));static int visible_and_exported __P((SHELL_VAR *));static int export_environment_candidate __P((SHELL_VAR *));static int local_and_exported __P((SHELL_VAR *));static int variable_in_context __P((SHELL_VAR *));#if defined (ARRAY_VARS)static int visible_array_vars __P((SHELL_VAR *));#endifstatic SHELL_VAR *bind_tempenv_variable __P((const char *, char *));static void push_temp_var __P((PTR_T));static void propagate_temp_var __P((PTR_T));static void dispose_temporary_env __P((sh_free_func_t *)); static inline char *mk_env_string __P((const char *, const char *));static char **make_env_array_from_var_list __P((SHELL_VAR **));static char **make_var_export_array __P((VAR_CONTEXT *));static char **make_func_export_array __P((void));static void add_temp_array_to_env __P((char **, int, int));static int n_shell_variables __P((void));static int set_context __P((SHELL_VAR *));static void push_func_var __P((PTR_T));static void push_exported_var __P((PTR_T));static inline int find_special_var __P((const char *));static voidcreate_variable_tables (){ if (shell_variables == 0) { shell_variables = global_variables = new_var_context ((char *)NULL, 0); shell_variables->scope = 0; shell_variables->table = hash_create (0); } if (shell_functions == 0) shell_functions = hash_create (0);#if defined (DEBUGGER) if (shell_function_defs == 0) shell_function_defs = hash_create (0);#endif}/* Initialize the shell variables from the current environment. If PRIVMODE is nonzero, don't import functions from ENV or parse $SHELLOPTS. */voidinitialize_shell_variables (env, privmode) char **env; int privmode;{ char *name, *string, *temp_string; int c, char_index, string_index, string_length; SHELL_VAR *temp_var; create_variable_tables (); for (string_index = 0; string = env[string_index++]; ) { char_index = 0; name = string; while ((c = *string++) && c != '=') ; if (string[-1] == '=') char_index = string - name - 1; /* If there are weird things in the environment, like `=xxx' or a string without an `=', just skip them. */ if (char_index == 0) continue; /* ASSERT(name[char_index] == '=') */ name[char_index] = '\0'; /* Now, name = env variable name, string = env variable value, and char_index == strlen (name) */ temp_var = (SHELL_VAR *)NULL; /* If exported function, define it now. Don't import functions from the environment in privileged mode. */ if (privmode == 0 && read_but_dont_execute == 0 && STREQN ("() {", string, 4)) { string_length = strlen (string); temp_string = (char *)xmalloc (3 + string_length + char_index); strcpy (temp_string, name); temp_string[char_index] = ' '; strcpy (temp_string + char_index + 1, string); parse_and_execute (temp_string, name, SEVAL_NONINT|SEVAL_NOHIST); /* Ancient backwards compatibility. Old versions of bash exported functions like name()=() {...} */ if (name[char_index - 1] == ')' && name[char_index - 2] == '(') name[char_index - 2] = '\0'; if (temp_var = find_function (name)) { VSETATTR (temp_var, (att_exported|att_imported)); array_needs_making = 1; } else report_error (_("error importing function definition for `%s'"), name); /* ( */ if (name[char_index - 1] == ')' && name[char_index - 2] == '\0') name[char_index - 2] = '('; /* ) */ }#if defined (ARRAY_VARS)# if 0 /* Array variables may not yet be exported. */ else if (*string == '(' && string[1] == '[' && string[strlen (string) - 1] == ')') { string_length = 1; temp_string = extract_array_assignment_list (string, &string_length); temp_var = assign_array_from_string (name, temp_string); FREE (temp_string); VSETATTR (temp_var, (att_exported | att_imported)); array_needs_making = 1; }# endif#endif#if 0 else if (legal_identifier (name))#else else#endif { temp_var = bind_variable (name, string, 0); if (temp_var) { if (legal_identifier (name)) VSETATTR (temp_var, (att_exported | att_imported)); else VSETATTR (temp_var, (att_exported | att_imported | att_invisible)); array_needs_making = 1; } } name[char_index] = '='; /* temp_var can be NULL if it was an exported function with a syntax error (a different bug, but it still shouldn't dump core). */ if (temp_var && function_p (temp_var) == 0) /* XXX not yet */ { CACHE_IMPORTSTR (temp_var, name); } } set_pwd (); /* Set up initial value of $_ */ temp_var = set_if_not ("_", dollar_vars[0]); /* Remember this pid. */ dollar_dollar_pid = getpid (); /* Now make our own defaults in case the vars that we think are important are missing. */ temp_var = set_if_not ("PATH", DEFAULT_PATH_VALUE);#if 0 set_auto_export (temp_var); /* XXX */#endif temp_var = set_if_not ("TERM", "dumb");#if 0 set_auto_export (temp_var); /* XXX */#endif#if defined (__QNX__) /* set node id -- don't import it from the environment */ { char node_name[22];# if defined (__QNXNTO__) netmgr_ndtostr(ND2S_LOCAL_STR, ND_LOCAL_NODE, node_name, sizeof(node_name));# else qnx_nidtostr (getnid (), node_name, sizeof (node_name));# endif temp_var = bind_variable ("NODE", node_name, 0); set_auto_export (temp_var); }#endif /* set up the prompts. */ if (interactive_shell) {#if defined (PROMPT_STRING_DECODE) set_if_not ("PS1", primary_prompt);#else if (current_user.uid == -1) get_current_user_info (); set_if_not ("PS1", current_user.euid == 0 ? "# " : primary_prompt);#endif set_if_not ("PS2", secondary_prompt); } set_if_not ("PS4", "+ "); /* Don't allow IFS to be imported from the environment. */ temp_var = bind_variable ("IFS", " \t\n", 0); setifs (temp_var); /* Magic machine types. Pretty convenient. */ set_machine_vars (); /* Default MAILCHECK for interactive shells. Defer the creation of a default MAILPATH until the startup files are read, because MAIL names a mail file if MAILPATH is not set, and we should provide a default only if neither is set. */ if (interactive_shell) { temp_var = set_if_not ("MAILCHECK", posixly_correct ? "600" : "60"); VSETATTR (temp_var, att_integer); } /* Do some things with shell level. */ initialize_shell_level (); set_ppid (); /* Initialize the `getopts' stuff. */ temp_var = bind_variable ("OPTIND", "1", 0); VSETATTR (temp_var, att_integer); getopts_reset (0); bind_variable ("OPTERR", "1", 0); sh_opterr = 1; if (login_shell == 1 && posixly_correct == 0) set_home_var (); /* Get the full pathname to THIS shell, and set the BASH variable to it. */ name = get_bash_name (); temp_var = bind_variable ("BASH", name, 0); free (name); /* Make the exported environment variable SHELL be the user's login shell. Note that the `tset' command looks at this variable to determine what style of commands to output; if it ends in "csh", then C-shell commands are output, else Bourne shell commands. */ set_shell_var (); /* Make a variable called BASH_VERSION which contains the version info. */ bind_variable ("BASH_VERSION", shell_version_string (), 0);#if defined (ARRAY_VARS) make_vers_array ();#endif if (command_execution_string) bind_variable ("BASH_EXECUTION_STRING", command_execution_string, 0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -