commit bash-20100318 snapshot

This commit is contained in:
Chet Ramey
2011-12-12 21:56:08 -05:00
parent 640b1cb0f7
commit 1b13a2904a
20 changed files with 2397 additions and 78 deletions
+1
View File
@@ -1066,6 +1066,7 @@ tests/type.tests f
tests/type.right f
tests/type1.sub f
tests/type2.sub f
tests/type3.sub f
tests/varenv.right f
tests/varenv.sh f
tests/varenv1.sub f
+1
View File
@@ -415,6 +415,7 @@ lib/sh/snprintf.c f
lib/sh/spell.c f
lib/sh/strcasecmp.c f
lib/sh/strcasestr.c f
lib/sh/strchrnul.c f
lib/sh/strerror.c f
lib/sh/strftime.c f
lib/sh/stringlist.c f
+3
View File
@@ -751,6 +751,9 @@ bash_add_history (line)
chars_to_add = "";
}
if (dstack.delimiter_depth == 0 && current->line[curlen - 1] == '\n' && *chars_to_add == ';')
chars_to_add++;
new_line = (char *)xmalloc (1
+ curlen
+ strlen (line)
+898
View File
@@ -0,0 +1,898 @@
/* bashhist.c -- bash interface to the GNU history library. */
/* Copyright (C) 1993-2009 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"
#if defined (HISTORY)
#if defined (HAVE_UNISTD_H)
# ifdef _MINIX
# include <sys/types.h>
# endif
# include <unistd.h>
#endif
#include "bashtypes.h"
#include <stdio.h>
#include <errno.h>
#include "bashansi.h"
#include "posixstat.h"
#include "filecntl.h"
#include "bashintl.h"
#if defined (SYSLOG_HISTORY)
# include <syslog.h>
#endif
#include "shell.h"
#include "flags.h"
#include "input.h"
#include "parser.h" /* for the struct dstack stuff. */
#include "pathexp.h" /* for the struct ignorevar stuff */
#include "bashhist.h" /* matching prototypes and declarations */
#include "builtins/common.h"
#include <readline/history.h>
#include <glob/glob.h>
#include <glob/strmatch.h>
#if defined (READLINE)
# include "bashline.h"
extern int rl_done, rl_dispatching; /* should really include readline.h */
#endif
#if !defined (errno)
extern int errno;
#endif
static int histignore_item_func __P((struct ign *));
static int check_history_control __P((char *));
static void hc_erasedups __P((char *));
static void really_add_history __P((char *));
static struct ignorevar histignore =
{
"HISTIGNORE",
(struct ign *)0,
0,
(char *)0,
(sh_iv_item_func_t *)histignore_item_func,
};
#define HIGN_EXPAND 0x01
/* Declarations of bash history variables. */
/* Non-zero means to remember lines typed to the shell on the history
list. This is different than the user-controlled behaviour; this
becomes zero when we read lines from a file, for example. */
int remember_on_history = 1;
int enable_history_list = 1; /* value for `set -o history' */
/* The number of lines that Bash has added to this history session. The
difference between the number of the top element in the history list
(offset from history_base) and the number of lines in the history file.
Appending this session's history to the history file resets this to 0. */
int history_lines_this_session;
/* The number of lines that Bash has read from the history file. */
int history_lines_in_file;
#if defined (BANG_HISTORY)
/* Non-zero means do no history expansion on this line, regardless
of what history_expansion says. */
int history_expansion_inhibited;
#endif
/* With the old default, every line was saved in the history individually.
I.e., if the user enters:
bash$ for i in a b c
> do
> echo $i
> done
Each line will be individually saved in the history.
bash$ history
10 for i in a b c
11 do
12 echo $i
13 done
14 history
If the variable command_oriented_history is set, multiple lines
which form one command will be saved as one history entry.
bash$ for i in a b c
> do
> echo $i
> done
bash$ history
10 for i in a b c
do
echo $i
done
11 history
The user can then recall the whole command all at once instead
of just being able to recall one line at a time.
This is now enabled by default.
*/
int command_oriented_history = 1;
/* Set to 1 if the first line of a possibly-multi-line command was saved
in the history list. Managed by maybe_add_history(), but global so
the history-manipluating builtins can see it. */
int current_command_first_line_saved = 0;
/* Non-zero means to store newlines in the history list when using
command_oriented_history rather than trying to use semicolons. */
int literal_history;
/* Non-zero means to append the history to the history file at shell
exit, even if the history has been stifled. */
int force_append_history;
/* A nit for picking at history saving. Flags have the following values:
Value == 0 means save all lines parsed by the shell on the history.
Value & HC_IGNSPACE means save all lines that do not start with a space.
Value & HC_IGNDUPS means save all lines that do not match the last
line saved.
Value & HC_ERASEDUPS means to remove all other matching lines from the
history list before saving the latest line. */
int history_control;
/* Set to 1 if the last command was added to the history list successfully
as a separate history entry; set to 0 if the line was ignored or added
to a previous entry as part of command-oriented-history processing. */
int hist_last_line_added;
/* Set to 1 if builtins/history.def:push_history added the last history
entry. */
int hist_last_line_pushed;
#if defined (READLINE)
/* If non-zero, and readline is being used, the user is offered the
chance to re-edit a failed history expansion. */
int history_reediting;
/* If non-zero, and readline is being used, don't directly execute a
line with history substitution. Reload it into the editing buffer
instead and let the user further edit and confirm with a newline. */
int hist_verify;
#endif /* READLINE */
/* Non-zero means to not save function definitions in the history list. */
int dont_save_function_defs;
/* Variables declared in other files used here. */
extern int current_command_line_count;
extern struct dstack dstack;
static int bash_history_inhibit_expansion __P((char *, int));
#if defined (READLINE)
static void re_edit __P((char *));
#endif
static int history_expansion_p __P((char *));
static int shell_comment __P((char *));
static int should_expand __P((char *));
static HIST_ENTRY *last_history_entry __P((void));
static char *expand_histignore_pattern __P((char *));
static int history_should_ignore __P((char *));
/* Is the history expansion starting at string[i] one that should not
be expanded? */
static int
bash_history_inhibit_expansion (string, i)
char *string;
int i;
{
/* The shell uses ! as a pattern negation character in globbing [...]
expressions, so let those pass without expansion. */
if (i > 0 && (string[i - 1] == '[') && member (']', string + i + 1))
return (1);
/* The shell uses ! as the indirect expansion character, so let those
expansions pass as well. */
else if (i > 1 && string[i - 1] == '{' && string[i - 2] == '$' &&
member ('}', string + i + 1))
return (1);
#if defined (EXTENDED_GLOB)
else if (extended_glob && i > 1 && string[i+1] == '(' && member (')', string + i + 2))
return (1);
#endif
else
return (0);
}
void
bash_initialize_history ()
{
history_quotes_inhibit_expansion = 1;
history_search_delimiter_chars = ";&()|<>";
history_inhibit_expansion_function = bash_history_inhibit_expansion;
#if defined (BANG_HISTORY)
sv_histchars ("histchars");
#endif
}
void
bash_history_reinit (interact)
int interact;
{
#if defined (BANG_HISTORY)
history_expansion = interact != 0;
history_expansion_inhibited = 1;
#endif
remember_on_history = enable_history_list = interact != 0;
history_inhibit_expansion_function = bash_history_inhibit_expansion;
}
void
bash_history_disable ()
{
remember_on_history = 0;
#if defined (BANG_HISTORY)
history_expansion_inhibited = 1;
#endif
}
void
bash_history_enable ()
{
remember_on_history = 1;
#if defined (BANG_HISTORY)
history_expansion_inhibited = 0;
#endif
history_inhibit_expansion_function = bash_history_inhibit_expansion;
sv_history_control ("HISTCONTROL");
sv_histignore ("HISTIGNORE");
}
/* Load the history list from the history file. */
void
load_history ()
{
char *hf;
/* Truncate history file for interactive shells which desire it.
Note that the history file is automatically truncated to the
size of HISTSIZE if the user does not explicitly set the size
differently. */
set_if_not ("HISTSIZE", "500");
sv_histsize ("HISTSIZE");
set_if_not ("HISTFILESIZE", get_string_value ("HISTSIZE"));
sv_histsize ("HISTFILESIZE");
/* Read the history in HISTFILE into the history list. */
hf = get_string_value ("HISTFILE");
if (hf && *hf && file_exists (hf))
{
read_history (hf);
using_history ();
history_lines_in_file = where_history ();
}
}
void
bash_clear_history ()
{
clear_history ();
history_lines_this_session = 0;
}
/* Delete and free the history list entry at offset I. */
int
bash_delete_histent (i)
int i;
{
HIST_ENTRY *discard;
discard = remove_history (i);
if (discard)
free_history_entry (discard);
history_lines_this_session--;
return 1;
}
int
bash_delete_last_history ()
{
register int i;
HIST_ENTRY **hlist, *histent;
int r;
hlist = history_list ();
if (hlist == NULL)
return 0;
for (i = 0; hlist[i]; i++)
;
i--;
/* History_get () takes a parameter that must be offset by history_base. */
histent = history_get (history_base + i); /* Don't free this */
if (histent == NULL)
return 0;
r = bash_delete_histent (i);
if (where_history () > history_length)
history_set_pos (history_length);
return r;
}
#ifdef INCLUDE_UNUSED
/* Write the existing history out to the history file. */
void
save_history ()
{
char *hf;
hf = get_string_value ("HISTFILE");
if (hf && *hf && file_exists (hf))
{
/* Append only the lines that occurred this session to
the history file. */
using_history ();
if (history_lines_this_session < where_history () || force_append_history)
append_history (history_lines_this_session, hf);
else
write_history (hf);
sv_histsize ("HISTFILESIZE");
}
}
#endif
int
maybe_append_history (filename)
char *filename;
{
int fd, result;
struct stat buf;
result = EXECUTION_SUCCESS;
if (history_lines_this_session && (history_lines_this_session < where_history ()))
{
/* If the filename was supplied, then create it if necessary. */
if (stat (filename, &buf) == -1 && errno == ENOENT)
{
fd = open (filename, O_WRONLY|O_CREAT, 0600);
if (fd < 0)
{
builtin_error (_("%s: cannot create: %s"), filename, strerror (errno));
return (EXECUTION_FAILURE);
}
close (fd);
}
result = append_history (history_lines_this_session, filename);
history_lines_in_file += history_lines_this_session;
history_lines_this_session = 0;
}
return (result);
}
/* If this is an interactive shell, then append the lines executed
this session to the history file. */
int
maybe_save_shell_history ()
{
int result;
char *hf;
result = 0;
if (history_lines_this_session)
{
hf = get_string_value ("HISTFILE");
if (hf && *hf)
{
/* If the file doesn't exist, then create it. */
if (file_exists (hf) == 0)
{
int file;
file = open (hf, O_CREAT | O_TRUNC | O_WRONLY, 0600);
if (file != -1)
close (file);
}
/* Now actually append the lines if the history hasn't been
stifled. If the history has been stifled, rewrite the
history file. */
using_history ();
if (history_lines_this_session <= where_history () || force_append_history)
{
result = append_history (history_lines_this_session, hf);
history_lines_in_file += history_lines_this_session;
}
else
{
result = write_history (hf);
history_lines_in_file = history_lines_this_session;
}
history_lines_this_session = 0;
sv_histsize ("HISTFILESIZE");
}
}
return (result);
}
#if defined (READLINE)
/* Tell readline () that we have some text for it to edit. */
static void
re_edit (text)
char *text;
{
if (bash_input.type == st_stdin)
bash_re_edit (text);
}
#endif /* READLINE */
/* Return 1 if this line needs history expansion. */
static int
history_expansion_p (line)
char *line;
{
register char *s;
for (s = line; *s; s++)
if (*s == history_expansion_char || *s == history_subst_char)
return 1;
return 0;
}
/* Do pre-processing on LINE. If PRINT_CHANGES is non-zero, then
print the results of expanding the line if there were any changes.
If there is an error, return NULL, otherwise the expanded line is
returned. If ADDIT is non-zero the line is added to the history
list after history expansion. ADDIT is just a suggestion;
REMEMBER_ON_HISTORY can veto, and does.
Right now this does history expansion. */
char *
pre_process_line (line, print_changes, addit)
char *line;
int print_changes, addit;
{
char *history_value;
char *return_value;
int expanded;
return_value = line;
expanded = 0;
# if defined (BANG_HISTORY)
/* History expand the line. If this results in no errors, then
add that line to the history if ADDIT is non-zero. */
if (!history_expansion_inhibited && history_expansion && history_expansion_p (line))
{
expanded = history_expand (line, &history_value);
if (expanded)
{
if (print_changes)
{
if (expanded < 0)
internal_error ("%s", history_value);
#if defined (READLINE)
else if (hist_verify == 0 || expanded == 2)
#else
else
#endif
fprintf (stderr, "%s\n", history_value);
}
/* If there was an error, return NULL. */
if (expanded < 0 || expanded == 2) /* 2 == print only */
{
# if defined (READLINE)
if (expanded == 2 && rl_dispatching == 0 && *history_value)
# else
if (expanded == 2 && *history_value)
# endif /* !READLINE */
maybe_add_history (history_value);
free (history_value);
# if defined (READLINE)
/* New hack. We can allow the user to edit the
failed history expansion. */
if (history_reediting && expanded < 0 && rl_done)
re_edit (line);
# endif /* READLINE */
return ((char *)NULL);
}
# if defined (READLINE)
if (hist_verify && expanded == 1)
{
re_edit (history_value);
return ((char *)NULL);
}
# endif
}
/* Let other expansions know that return_value can be free'ed,
and that a line has been added to the history list. Note
that we only add lines that have something in them. */
expanded = 1;
return_value = history_value;
}
# endif /* BANG_HISTORY */
if (addit && remember_on_history && *return_value)
maybe_add_history (return_value);
#if 0
if (expanded == 0)
return_value = savestring (line);
#endif
return (return_value);
}
/* Return 1 if the first non-whitespace character in LINE is a `#', indicating
* that the line is a shell comment. */
static int
shell_comment (line)
char *line;
{
char *p;
for (p = line; p && *p && whitespace (*p); p++)
;
return (p && *p == '#');
}
#ifdef INCLUDE_UNUSED
/* Remove shell comments from LINE. A `#' and anything after it is a comment.
This isn't really useful yet, since it doesn't handle quoting. */
static char *
filter_comments (line)
char *line;
{
char *p;
for (p = line; p && *p && *p != '#'; p++)
;
if (p && *p == '#')
*p = '\0';
return (line);
}
#endif
/* Check LINE against what HISTCONTROL says to do. Returns 1 if the line
should be saved; 0 if it should be discarded. */
static int
check_history_control (line)
char *line;
{
HIST_ENTRY *temp;
int r;
if (history_control == 0)
return 1;
/* ignorespace or ignoreboth */
if ((history_control & HC_IGNSPACE) && *line == ' ')
return 0;
/* ignoredups or ignoreboth */
if (history_control & HC_IGNDUPS)
{
using_history ();
temp = previous_history ();
r = (temp == 0 || STREQ (temp->line, line) == 0);
using_history ();
if (r == 0)
return r;
}
return 1;
}
/* Remove all entries matching LINE from the history list. Triggered when
HISTCONTROL includes `erasedups'. */
static void
hc_erasedups (line)
char *line;
{
HIST_ENTRY *temp;
int r;
using_history ();
while (temp = previous_history ())
{
if (STREQ (temp->line, line))
{
r = where_history ();
remove_history (r);
}
}
using_history ();
}
/* Add LINE to the history list, handling possibly multi-line compound
commands. We note whether or not we save the first line of each command
(which is usually the entire command and history entry), and don't add
the second and subsequent lines of a multi-line compound command if we
didn't save the first line. We don't usually save shell comment lines in
compound commands in the history, because they could have the effect of
commenting out the rest of the command when the entire command is saved as
a single history entry (when COMMAND_ORIENTED_HISTORY is enabled). If
LITERAL_HISTORY is set, we're saving lines in the history with embedded
newlines, so it's OK to save comment lines. We also make sure to save
multiple-line quoted strings or other constructs. */
void
maybe_add_history (line)
char *line;
{
hist_last_line_added = 0;
/* Don't use the value of history_control to affect the second
and subsequent lines of a multi-line command (old code did
this only when command_oriented_history is enabled). */
if (current_command_line_count > 1)
{
if (current_command_first_line_saved &&
(literal_history || dstack.delimiter_depth != 0 || shell_comment (line) == 0))
bash_add_history (line);
return;
}
/* This is the first line of a (possible multi-line) command. Note whether
or not we should save the first line and remember it. */
current_command_first_line_saved = check_add_history (line, 0);
}
/* Just check LINE against HISTCONTROL and HISTIGNORE and add it to the
history if it's OK. Used by `history -s' as well as maybe_add_history().
Returns 1 if the line was saved in the history, 0 otherwise. */
int
check_add_history (line, force)
char *line;
int force;
{
if (check_history_control (line) && history_should_ignore (line) == 0)
{
/* We're committed to saving the line. If the user has requested it,
remove other matching lines from the history. */
if (history_control & HC_ERASEDUPS)
hc_erasedups (line);
if (force)
{
really_add_history (line);
using_history ();
}
else
bash_add_history (line);
return 1;
}
return 0;
}
#if defined (SYSLOG_HISTORY)
#define SYSLOG_MAXLEN 600
void
bash_syslog_history (line)
const char *line;
{
char trunc[SYSLOG_MAXLEN];
if (strlen(line) < SYSLOG_MAXLEN)
syslog (SYSLOG_FACILITY|SYSLOG_LEVEL, "HISTORY: PID=%d UID=%d %s", getpid(), current_user.uid, line);
else
{
strncpy (trunc, line, SYSLOG_MAXLEN);
trunc[SYSLOG_MAXLEN - 1] = '\0';
syslog (SYSLOG_FACILITY|SYSLOG_LEVEL, "HISTORY (TRUNCATED): PID=%d UID=%d %s", getpid(), current_user.uid, trunc);
}
}
#endif
/* Add a line to the history list.
The variable COMMAND_ORIENTED_HISTORY controls the style of history
remembering; when non-zero, and LINE is not the first line of a
complete parser construct, append LINE to the last history line instead
of adding it as a new line. */
void
bash_add_history (line)
char *line;
{
int add_it, offset, curlen;
HIST_ENTRY *current, *old;
char *chars_to_add, *new_line;
add_it = 1;
if (command_oriented_history && current_command_line_count > 1)
{
chars_to_add = literal_history ? "\n" : history_delimiting_chars ();
using_history ();
current = previous_history ();
if (current)
{
/* If the previous line ended with an escaped newline (escaped
with backslash, but otherwise unquoted), then remove the quoted
newline, since that is what happens when the line is parsed. */
curlen = strlen (current->line);
if (dstack.delimiter_depth == 0 && current->line[curlen - 1] == '\\' &&
current->line[curlen - 2] != '\\')
{
current->line[curlen - 1] = '\0';
curlen--;
chars_to_add = "";
}
new_line = (char *)xmalloc (1
+ curlen
+ strlen (line)
+ strlen (chars_to_add));
sprintf (new_line, "%s%s%s", current->line, chars_to_add, line);
offset = where_history ();
old = replace_history_entry (offset, new_line, current->data);
free (new_line);
if (old)
free_history_entry (old);
add_it = 0;
}
}
if (add_it)
really_add_history (line);
#if defined (SYSLOG_HISTORY)
bash_syslog_history (line);
#endif
using_history ();
}
static void
really_add_history (line)
char *line;
{
hist_last_line_added = 1;
hist_last_line_pushed = 0;
add_history (line);
history_lines_this_session++;
}
int
history_number ()
{
using_history ();
return (remember_on_history ? history_base + where_history () : 1);
}
static int
should_expand (s)
char *s;
{
char *p;
for (p = s; p && *p; p++)
{
if (*p == '\\')
p++;
else if (*p == '&')
return 1;
}
return 0;
}
static int
histignore_item_func (ign)
struct ign *ign;
{
if (should_expand (ign->val))
ign->flags |= HIGN_EXPAND;
return (0);
}
void
setup_history_ignore (varname)
char *varname;
{
setup_ignore_patterns (&histignore);
}
static HIST_ENTRY *
last_history_entry ()
{
HIST_ENTRY *he;
using_history ();
he = previous_history ();
using_history ();
return he;
}
char *
last_history_line ()
{
HIST_ENTRY *he;
he = last_history_entry ();
if (he == 0)
return ((char *)NULL);
return he->line;
}
static char *
expand_histignore_pattern (pat)
char *pat;
{
HIST_ENTRY *phe;
char *ret;
phe = last_history_entry ();
if (phe == (HIST_ENTRY *)0)
return (savestring (pat));
ret = strcreplace (pat, '&', phe->line, 1);
return ret;
}
/* Return 1 if we should not put LINE into the history according to the
patterns in HISTIGNORE. */
static int
history_should_ignore (line)
char *line;
{
register int i, match;
char *npat;
if (histignore.num_ignores == 0)
return 0;
for (i = match = 0; i < histignore.num_ignores; i++)
{
if (histignore.ignores[i].flags & HIGN_EXPAND)
npat = expand_histignore_pattern (histignore.ignores[i].val);
else
npat = histignore.ignores[i].val;
match = strmatch (npat, line, FNMATCH_EXTFLAG) != FNM_NOMATCH;
if (histignore.ignores[i].flags & HIGN_EXPAND)
free (npat);
if (match)
break;
}
return match;
}
#endif /* HISTORY */
+2 -1
View File
@@ -615,13 +615,14 @@ add_char:
if (unbuffered_read == 0)
zsyncfd (fd);
discard_unwind_frame ("read_builtin");
retval = eof ? EXECUTION_FAILURE : EXECUTION_SUCCESS;
assign_vars:
interrupt_immediately--;
terminate_immediately--;
discard_unwind_frame ("read_builtin");
#if defined (ARRAY_VARS)
/* If -a was given, take the string read, break it into a list of words,
+1 -1
View File
@@ -3902,7 +3902,7 @@ turned on to be used in an expression.
.PP
Constants with a leading 0 are interpreted as octal numbers.
A leading 0x or 0X denotes hexadecimal.
Otherwise, numbers take the form [\fIbase#\fP]n, where \fIbase\fP
Otherwise, numbers take the form [\fIbase#\fP]n, where the optional \fIbase\fP
is a decimal number between 2 and 64 representing the arithmetic
base, and \fIn\fP is a number in that base.
If \fIbase#\fP is omitted, then base 10 is used.
+6 -5
View File
@@ -6055,7 +6055,7 @@ exit status of 124. If a shell function returns 124, and changes
the compspec associated with the command on which completion is being
attempted (supplied as the first argument when the function is executed),
programmable completion restarts from the beginning, with an
attempt to find a compspec for that command. This allows a set of
attempt to find a new compspec for that command. This allows a set of
completions to be built dynamically as completion is attempted, rather than
being loaded all at once.
.PP
@@ -7642,12 +7642,13 @@ It returns false if the end of options is encountered or an
error occurs.
.TP
\fBhash\fP [\fB\-lr\fP] [\fB\-p\fP \fIfilename\fP] [\fB\-dt\fP] [\fIname\fP]
For each
.IR name ,
the full file name of the command is determined by searching
Each time \fBhash\fP is invoked,
the full pathname of the command
.I name
is determined by searching
the directories in
.B $PATH
and remembered.
and remembered. Any previously-remembered pathname is discarded.
If the
.B \-p
option is supplied, no path search is performed, and
+1 -1
View File
@@ -5966,7 +5966,7 @@ to be used in an expression.
Constants with a leading 0 are interpreted as octal numbers.
A leading @samp{0x} or @samp{0X} denotes hexadecimal. Otherwise,
numbers take the form [@var{base}@code{#}]@var{n}, where @var{base}
numbers take the form [@var{base}@code{#}]@var{n}, where the optional @var{base}
is a decimal number between 2 and 64 representing the arithmetic
base, and @var{n} is a number in that base. If @var{base}@code{#} is
omitted, then base 10 is used.
+7 -6
View File
@@ -2986,10 +2986,12 @@ If @code{getopts} is silent, then a colon (@samp{:}) is placed in
@example
hash [-r] [-p @var{filename}] [-dt] [@var{name}]
@end example
Remember the full pathnames of commands specified as @var{name} arguments,
Each time @code{hash} is invoked, it remembers the full pathnames of the
commands specified as @var{name} arguments,
so they need not be searched for on subsequent invocations.
The commands are found by searching through the directories listed in
@env{$PATH}.
Any previously-remembered pathname is discarded.
The @option{-p} option inhibits the path search, and @var{filename} is
used as the location of @var{name}.
The @option{-r} option causes the shell to forget all remembered locations.
@@ -5316,8 +5318,9 @@ bash [long-opt] [-abefhkmnptuvxdBCDHP] [-o @var{option}] [-O @var{shopt_option}]
bash [long-opt] -s [-abefhkmnptuvxdBCDHP] [-o @var{option}] [-O @var{shopt_option}] [@var{argument} @dots{}]
@end example
In addition to the single-character shell command-line options
(@pxref{The Set Builtin}), there are several multi-character
All of the single-character options used with the @code{set} builtin
(@pxref{The Set Builtin}) can be used as options when the shell is invoked.
In addition, there are several multi-character
options that you can use. These options must appear on the command
line before the single-character options to be recognized.
@@ -5326,9 +5329,7 @@ line before the single-character options to be recognized.
Arrange for the debugger profile to be executed before the shell
starts. Turns on extended debugging mode (see @ref{The Shopt Builtin}
for a description of the @code{extdebug} option to the @code{shopt}
builtin) and shell function tracing
(see @ref{The Set Builtin} for a description of the @code{-o functrace}
option).
builtin).
@item --dump-po-strings
A list of all double-quoted strings preceded by @samp{$}
+8
View File
@@ -4816,7 +4816,15 @@ history_delimiting_chars ()
add the first line of the body of the here document (the second line
of the command). */
if (parser_state & PST_HEREDOC)
#if 0
{
if (last_read_token == WORD && (token_before_that == LESS_LESS || token_before_that == LESS_LESS_MINUS))
return ("\n"); /* XXX -- need to clean up in bash_add_history */
#endif
return (current_command_line_count == 2 ? "\n" : "");
#if 0
}
#endif
/* First, handle some special cases. */
/*(*/
+6 -19
View File
@@ -4816,7 +4816,11 @@ history_delimiting_chars ()
add the first line of the body of the here document (the second line
of the command). */
if (parser_state & PST_HEREDOC)
{
if (last_read_token == WORD && (token_before_that == LESS_LESS || token_before_that == LESS_LESS_MINUS))
return ("\n"); /* XXX -- need to clean up in bash_add_history */
return (current_command_line_count == 2 ? "\n" : "");
}
/* First, handle some special cases. */
/*(*/
@@ -5780,10 +5784,6 @@ sh_parser_state_t *
save_parser_state (ps)
sh_parser_state_t *ps;
{
#if defined (ARRAY_VARS)
SHELL_VAR *v;
#endif
if (ps == 0)
ps = (sh_parser_state_t *)xmalloc (sizeof (sh_parser_state_t));
if (ps == 0)
@@ -5806,11 +5806,7 @@ save_parser_state (ps)
ps->last_command_exit_value = last_command_exit_value;
#if defined (ARRAY_VARS)
v = find_variable ("PIPESTATUS");
if (v && array_p (v) && array_cell (v))
ps->pipestatus = array_copy (array_cell (v));
else
ps->pipestatus = (ARRAY *)NULL;
ps->pipestatus = save_pipestatus_array ();
#endif
ps->last_shell_builtin = last_shell_builtin;
@@ -5826,10 +5822,6 @@ void
restore_parser_state (ps)
sh_parser_state_t *ps;
{
#if defined (ARRAY_VARS)
SHELL_VAR *v;
#endif
if (ps == 0)
return;
@@ -5854,12 +5846,7 @@ restore_parser_state (ps)
last_command_exit_value = ps->last_command_exit_value;
#if defined (ARRAY_VARS)
v = find_variable ("PIPESTATUS");
if (v && array_p (v) && array_cell (v))
{
array_dispose (array_cell (v));
var_setarray (v, ps->pipestatus);
}
restore_pipestatus_array (ps->pipestatus);
#endif
last_shell_builtin = ps->last_shell_builtin;
+35 -37
View File
@@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: bash 4.1\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2009-12-30 08:25-0500\n"
"PO-Revision-Date: 2010-01-28 10:27+0800\n"
"PO-Revision-Date: 2010-03-14 16:16+0800\n"
"Last-Translator: Xin Ye <alyex.ye@gmail.com>\n"
"Language-Team: Chinese (simplified) <i18n-zh@googlegroups.com>\n"
"MIME-Version: 1.0\n"
@@ -101,7 +101,7 @@ msgstr "%s 未与任何键绑定。\n"
#: builtins/bind.def:307
#, c-format
msgid "%s can be invoked via "
msgstr ""
msgstr "%s 可以被调用,通过"
#: builtins/break.def:77 builtins/break.def:117
msgid "loop count"
@@ -439,17 +439,17 @@ msgstr "%s: 选项需要一个参数 -- %c\n"
#: builtins/hash.def:92
msgid "hashing disabled"
msgstr ""
msgstr "哈希已禁用"
#: builtins/hash.def:138
#, c-format
msgid "%s: hash table empty\n"
msgstr ""
msgstr "%s: 哈希表为空\n"
#: builtins/hash.def:244
#, c-format
msgid "hits\tcommand\n"
msgstr ""
msgstr "命中\t命令\n"
#: builtins/help.def:130
#, c-format
@@ -495,7 +495,7 @@ msgstr "%s: 历史扩展失败"
#: builtins/inlib.def:71
#, c-format
msgid "%s: inlib failed"
msgstr ""
msgstr "%s: inlib 失败"
#: builtins/jobs.def:109
msgid "no other options allowed with `-x'"
@@ -537,12 +537,12 @@ msgstr "%s: 无效的行数"
#: builtins/mapfile.def:277
#, c-format
msgid "%s: invalid array origin"
msgstr ""
msgstr "%s: 无效的数组基数"
#: builtins/mapfile.def:294
#, c-format
msgid "%s: invalid callback quantum"
msgstr ""
msgstr "%s: 无效的回调量子"
#: builtins/mapfile.def:326
msgid "empty array variable name"
@@ -569,7 +569,7 @@ msgstr "警告: %s: %s"
#: builtins/printf.def:757
msgid "missing hex digit for \\x"
msgstr ""
msgstr "使用了\\x但缺少十六进制数"
#: builtins/pushd.def:195
msgid "no other directory"
@@ -695,7 +695,7 @@ msgstr "%s: 不是函数"
#: builtins/shift.def:71 builtins/shift.def:77
msgid "shift count"
msgstr ""
msgstr "位移计数"
#: builtins/shopt.def:260
msgid "cannot set and unset shell options simultaneously"
@@ -720,7 +720,6 @@ msgid "cannot suspend"
msgstr "无法挂起"
#: builtins/suspend.def:111
#, fuzzy
msgid "cannot suspend a login shell"
msgstr "无法挂起一个登录shell"
@@ -752,12 +751,12 @@ msgstr "%s 是 %s\n"
#: builtins/type.def:337
#, c-format
msgid "%s is hashed (%s)\n"
msgstr ""
msgstr "%s 已被哈希 (%s)\n"
#: builtins/ulimit.def:372
#, c-format
msgid "%s: invalid limit argument"
msgstr ""
msgstr "%s: 无效的 limit 参数"
#: builtins/ulimit.def:398
#, c-format
@@ -767,16 +766,16 @@ msgstr "`%c': 坏的命令"
#: builtins/ulimit.def:427
#, c-format
msgid "%s: cannot get limit: %s"
msgstr ""
msgstr "%s: 无法获取 limit 值: %s"
#: builtins/ulimit.def:453
msgid "limit"
msgstr ""
msgstr "limit"
#: builtins/ulimit.def:465 builtins/ulimit.def:765
#, c-format
msgid "%s: cannot modify limit: %s"
msgstr ""
msgstr "%s: 无法修改 limit 值: %s"
#: builtins/umask.def:118
msgid "octal number"
@@ -785,12 +784,12 @@ msgstr "八进制数"
#: builtins/umask.def:231
#, c-format
msgid "`%c': invalid symbolic mode operator"
msgstr ""
msgstr "`%c': 无效的符号状态运算符"
#: builtins/umask.def:286
#, c-format
msgid "`%c': invalid symbolic mode character"
msgstr ""
msgstr "`%c': 无效的符号状态字符"
#: error.c:90 error.c:321 error.c:323 error.c:325
msgid " line "
@@ -816,11 +815,11 @@ msgstr "坏的命令类型"
#: error.c:408
msgid "bad connector"
msgstr ""
msgstr "坏的条件连接符"
#: error.c:409
msgid "bad jump"
msgstr ""
msgstr "坏的跳转"
#: error.c:447
#, c-format
@@ -830,7 +829,7 @@ msgstr "%s: 为绑定变量"
#: eval.c:181
#, c-format
msgid "\atimed out waiting for input: auto-logout\n"
msgstr ""
msgstr "\a 等待输入超时:自动登出\n"
#: execute_cmd.c:497
#, c-format
@@ -864,7 +863,7 @@ msgstr "%s: %s: 坏的解释器"
#: execute_cmd.c:4976
#, c-format
msgid "cannot duplicate fd %d to fd %d"
msgstr ""
msgstr "无法复制文件描述符 %d 到 文件描述符 %d"
#: expr.c:241
msgid "expression recursion level exceeded"
@@ -872,7 +871,7 @@ msgstr "表达式递归层次越界"
#: expr.c:265
msgid "recursion stack underflow"
msgstr ""
msgstr "递归栈下溢"
#: expr.c:379
msgid "syntax error in expression"
@@ -888,7 +887,7 @@ msgstr "除0"
#: expr.c:471
msgid "bug: bad expassign token"
msgstr ""
msgstr "错误:坏的表达式赋值符号"
#: expr.c:513
msgid "`:' expected for conditional expression"
@@ -896,11 +895,11 @@ msgstr "条件表达式期待 `:'"
#: expr.c:781
msgid "exponent less than 0"
msgstr ""
msgstr "指数小于0"
#: expr.c:826
msgid "identifier expected after pre-increment or pre-decrement"
msgstr ""
msgstr "预增符或预减符后应跟有标识符"
#: expr.c:854
msgid "missing `)'"
@@ -917,15 +916,15 @@ msgstr "语法错误: 无效的算术运算符"
#: expr.c:1202
#, c-format
msgid "%s%s%s: %s (error token is \"%s\")"
msgstr ""
msgstr "%s%s%s: %s (错误符号是 \"%s\""
#: expr.c:1260
msgid "invalid arithmetic base"
msgstr ""
msgstr "无效的算数进制"
#: expr.c:1280
msgid "value too great for base"
msgstr ""
msgstr "数值太大不可为算数进制的基"
#: expr.c:1329
#, c-format
@@ -939,17 +938,17 @@ msgstr "getcwd: 无法访问父目录"
#: input.c:94 subst.c:4857
#, c-format
msgid "cannot reset nodelay mode for fd %d"
msgstr ""
msgstr "无法为文件描述符 %d 重置nodelay模式"
#: input.c:258
#, c-format
msgid "cannot allocate new file descriptor for bash input from fd %d"
msgstr ""
msgstr "无法从文件描述符 %d 为 bash 的输入获取一个新的文件描述符"
#: input.c:266
#, c-format
msgid "save_bash_input: buffer already exists for new fd %d"
msgstr ""
msgstr "save_bash_input: 已经存在新的文件描述符 %d 的缓冲区"
#: jobs.c:466
msgid "start_pipeline: pgrp pipe"
@@ -1203,7 +1202,6 @@ msgid "setlocale: %s: cannot change locale (%s): %s"
msgstr ""
#: mailcheck.c:433
#, fuzzy
msgid "You have mail in $_"
msgstr "您在 $_ 中有邮件"
@@ -1837,17 +1835,17 @@ msgstr ""
#: version.c:47
msgid "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\n"
msgstr ""
msgstr "许可证 GPLv3+: GNU GPL 许可证版本3或者更高 <http://gnu.org/licenses/gpl.html>\n"
#: version.c:86 version2.c:83
#, c-format
msgid "GNU bash, version %s (%s)\n"
msgstr ""
msgstr "GNU bash, 版本 %s (%s)\n"
#: version.c:91 version2.c:88
#, c-format
msgid "This is free software; you are free to change and redistribute it.\n"
msgstr ""
msgstr "这是自由软件,您可以自由地更改和重新发布。\n"
#: version.c:92 version2.c:89
#, c-format
@@ -1862,7 +1860,7 @@ msgstr ""
#: version2.c:87
#, c-format
msgid "License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html>\n"
msgstr ""
msgstr "许可证 GPLv2+: GNU GPL 许可证版本2或者更高 <http://gnu.org/licenses/gpl.html>\n"
#: xmalloc.c:91
#, c-format
+17 -4
View File
@@ -113,6 +113,12 @@ FILE *xtrace_fp = 0;
#define CHECK_XTRACE_FP xtrace_fp = (xtrace_fp ? xtrace_fp : stderr)
#define PRINT_DEFERRED_HEREDOCS(x) \
do { \
if (deferred_heredocs) \
print_deferred_heredocs (x); \
} while (0)
/* Non-zero means the stuff being printed is inside of a function def. */
static int inside_function_def;
static int skip_this_indent;
@@ -293,8 +299,7 @@ make_command_string_internal (command)
}
make_command_string_internal (command->value.Connection->second);
if (deferred_heredocs)
print_deferred_heredocs ("");
PRINT_DEFERRED_HEREDOCS ("");
printing_connection--;
break;
@@ -560,13 +565,15 @@ print_for_command (for_command)
FOR_COM *for_command;
{
print_for_command_head (for_command);
cprintf (";");
newline ("do\n");
indentation += indentation_amount;
make_command_string_internal (for_command->action);
PRINT_DEFERRED_HEREDOCS ("");
semicolon ();
indentation -= indentation_amount;
newline ("done");
}
@@ -620,6 +627,7 @@ print_select_command (select_command)
newline ("do\n");
indentation += indentation_amount;
make_command_string_internal (select_command->action);
PRINT_DEFERRED_HEREDOCS ("");
semicolon ();
indentation -= indentation_amount;
newline ("done");
@@ -703,6 +711,7 @@ print_case_clauses (clauses)
indentation += indentation_amount;
make_command_string_internal (clauses->action);
indentation -= indentation_amount;
PRINT_DEFERRED_HEREDOCS ("");
if (clauses->flags & CASEPAT_FALLTHROUGH)
newline (";&");
else if (clauses->flags & CASEPAT_TESTNEXT)
@@ -736,10 +745,12 @@ print_until_or_while (while_command, which)
cprintf ("%s ", which);
skip_this_indent++;
make_command_string_internal (while_command->test);
PRINT_DEFERRED_HEREDOCS ("");
semicolon ();
cprintf (" do\n"); /* was newline ("do\n"); */
indentation += indentation_amount;
make_command_string_internal (while_command->action);
PRINT_DEFERRED_HEREDOCS ("");
indentation -= indentation_amount;
semicolon ();
newline ("done");
@@ -756,6 +767,7 @@ print_if_command (if_command)
cprintf (" then\n");
indentation += indentation_amount;
make_command_string_internal (if_command->true_case);
PRINT_DEFERRED_HEREDOCS ("");
indentation -= indentation_amount;
if (if_command->false_case)
@@ -764,6 +776,7 @@ print_if_command (if_command)
newline ("else\n");
indentation += indentation_amount;
make_command_string_internal (if_command->false_case);
PRINT_DEFERRED_HEREDOCS ("");
indentation -= indentation_amount;
}
semicolon ();
@@ -943,7 +956,7 @@ print_deferred_heredocs (cstring)
cprintf (" ");
print_heredoc_header (hdtail);
}
if (cstring[0] != ';' || cstring[1])
if (cstring[0] && (cstring[0] != ';' || cstring[1]))
cprintf ("%s", cstring);
if (deferred_heredocs)
cprintf ("\n");
+4 -3
View File
@@ -155,7 +155,7 @@ static void
make_command_string_internal (command)
COMMAND *command;
{
char s[3], *op;
char s[3];
if (command == 0)
cprintf ("");
@@ -565,6 +565,8 @@ print_for_command (for_command)
newline ("do\n");
indentation += indentation_amount;
make_command_string_internal (for_command->action);
if (deferred_heredocs)
print_deferred_heredocs ("");
semicolon ();
indentation -= indentation_amount;
newline ("done");
@@ -1052,10 +1054,9 @@ static void
print_redirection (redirect)
REDIRECT *redirect;
{
int kill_leading, redirector, redir_fd;
int redirector, redir_fd;
WORD_DESC *redirectee, *redir_word;
kill_leading = 0;
redirectee = redirect->redirectee.filename;
redir_fd = redirect->redirectee.dest;
+1279
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,4 +1,4 @@
BUILD_DIR=/usr/local/build/chet/bash/bash-current
BUILD_DIR=/usr/local/build/bash/bash-current
THIS_SH=$BUILD_DIR/bash
PATH=$PATH:$BUILD_DIR
+16
View File
@@ -80,3 +80,19 @@ qux
bar
qux
foo is a function
foo ()
{
rm -f a b c;
for f in a b c;
do
cat >> ${f} <<-EOF
file
EOF
done
grep . a b c
}
a:file
b:file
c:file
+2
View File
@@ -91,3 +91,5 @@ type f | cat -v
${THIS_SH} type1.sub
${THIS_SH} type2.sub
${THIS_SH} type3.sub
+93
View File
@@ -0,0 +1,93 @@
set +o posix
hash -r
unalias -a
# this should echo nothing
type
# this should be a usage error
type -r ${THIS_SH}
# these should behave identically
type notthere
command -v notthere
alias m=more
unset -f func 2>/dev/null
func() { echo this is func; }
type -t func
type -t while
type -t builtin
type -t /bin/sh
type -t ${THIS_SH}
type -t mv
type func
# the following two should produce identical output
type while
type -a while
type builtin
type /bin/sh
command -v func
command -V func
command -v while
command -V while
# the following two lines should produce the same output
# post-3.0 patch makes command -v silent, as posix specifies
# first test with alias expansion off (should all fail or produce no output)
type -t m
type m
command -v m
alias -p
alias m
# then test with alias expansion on
shopt -s expand_aliases
type m
type -t m
command -v m
alias -p
alias m
command -V m
shopt -u expand_aliases
command -v builtin
command -V builtin
command -v /bin/sh
command -V /bin/sh
unset -f func
type func
unalias m
type m
hash -r
hash -p /bin/sh sh
type -p sh
SHBASE=${THIS_SH##*/}
hash -p /tmp/$SHBASE $SHBASE
type -p $SHBASE
type $SHBASE
type -t $SHBASE
# make sure the hash table looks right
hash
# bug in versions of bash up to and including bash-3.2
f() {
v=$'\001'
}
type f | cat -v
${THIS_SH} type1.sub
${THIS_SH} type2.sub
+16
View File
@@ -0,0 +1,16 @@
foo() {
rm -f a b c
for f in a b c; do
cat <<-EOF >> ${f}
file
EOF
done
grep . a b c
}
type foo
eval "$(type foo | sed 1d)"
foo
rm -f a b c