option processing as bindable command names for which to print any key
bindings.
+69. Interactive shells will notify the user of completed jobs while sourcing
+ a script. Newer versions defer notification until script execution
+ completes.
+
Shell Compatibility Level
=========================
expressions composed of five or more primaries.
- the -p and -P options to the bind builtin treat remaining arguments
as bindable command names for which to print any key bindings
-
+ - interactive shells will notify the user of completed jobs while
+ sourcing a script. Newer versions defer notification until script
+ execution completes.
-------------------------------------------------------------------------------
Copying and distribution of this file, with or without modification,
- Readline Introduction: expand description of the Meta key and the
various things it can do, reference force-meta-prefix and
enable-meta-key
+
+ 8/26
+ ----
+doc/bashref.texi
+ - case: add process substitution to the list of expansions for the
+ word.
+ Reported by shynur <one.last.kiss@outlook.com>
+
+execute_cmd.c
+ - execute_null_command: if an empty simple command (no words, just
+ redirections) requires a fork, reset top_level and exit if we
+ longjmp there. This can happen with an expansion error while we
+ evaluate the redirection.
+ Report from youheng.lue@gmail.com
+ - execute_connection: in default mode, bash performs jobs notifications
+ in an interactive shell between commands separated by ';' or '\n'.
+ It shouldn't do this in posix mode, since posix now specifies when
+ notifications can take place
+
+examples/loadables/{realpath,csv,dsv,cut,stat,kv}
+ - changes to make them build when arrays are not available
+ Report from Dennis Clarke <dclarke@blastwave.org>
+
+jobs.c
+ - notify_and_cleanup: make interactive shells notifying during sourced
+ scripts dependent on the shell compatibility level and inactive in
+ versions beyond bash-5.2
+ Inspired by report from Zachary Santer <zsanter@gmail.com>
+
+doc/bashref.texi
+ - Bash posix mode: note the change with job notifications in command
+ lists
+ - Shell compatibility mode: note job notification changes for compat
+ level > 52
+
+parse.y
+ - CHECK_FOR_RESERVED_WORD: call set_word_top here on the reserved word
+ token about to be returned; don't worry about trying to set it after
+ the fact
+ Report from Collin Funk <collin.funk1@gmail.com>
tests/errors9.sub f
tests/errors10.sub f
tests/errors11.sub f
+tests/errors12.sub f
tests/execscript f
tests/exec.right f
tests/exec1.sub f 755
#endif
}
+#if defined (READLINE)
void
reset_rl_instream (FILE *save_instream)
{
{
reset_rl_instream (fp);
}
+#endif
/* Read the value of the shell variables whose names follow.
The reading is done from the current input stream, whatever
Expands to the positional parameters, starting from one.
When the expansion is not within double quotes, each positional parameter
expands to a separate word.
-In contexts where it is performed, those words
+In contexts where these expansions are performed, those words
are subject to further word splitting and pathname expansion.
When the expansion occurs within double quotes, it expands to a single word
with the value of each parameter separated by the first character of the
Each clause must be terminated with @samp{;;}, @samp{;&}, or @samp{;;&}.
The @var{word} undergoes tilde expansion, parameter expansion, command
-substitution, arithmetic expansion, and quote removal
+substitution, process substitution, arithmetic expansion, and quote removal
(@pxref{Shell Parameter Expansion})
-before matching is attempted.
+before the shell attempts to match the pattern.
Each @var{pattern} undergoes tilde expansion, parameter expansion,
command substitution, arithmetic expansion, process substitution, and
quote removal.
($*) Expands to the positional parameters, starting from one.
When the expansion is not within double quotes, each positional parameter
expands to a separate word.
-In contexts where it is performed, those words
+In contexts where these expansions are performed, those words
are subject to further word splitting and filename expansion.
When the expansion occurs within double quotes, it expands to a single word
with the value of each parameter separated by the first character of the
is stopped is `Stopped(@var{signame})', where @var{signame} is, for
example, @code{SIGTSTP}.
+@item
+Bash does not perform job notifications between executing commands in
+lists separated by @samp{;} or newline in interactive shells.
+
@item
Alias expansion is always enabled, even in non-interactive shells.
as bindable command names, and
displays any key sequences bound to those commands, instead of treating
the arguments as key sequences to bind.
+@item
+Interactive shells will notify the user of completed jobs while sourcing a
+script.
+Newer versions defer notification until script execution completes.
@end itemize
@end table
Copyright (C) 1988-2024 Free Software Foundation, Inc.
@end ignore
-@set LASTCHANGE Fri Aug 16 17:10:06 EDT 2024
-
+@set LASTCHANGE Mon Aug 26 11:29:52 EDT 2024
@set EDITION 5.3
@set VERSION 5.3
-@set UPDATED 16 August 2024
+@set UPDATED 26 August 2024
@set UPDATED-MONTH August 2024
#include "loadables.h"
+#if defined (ARRAY_VARS)
+
#define CSV_ARRAY_DEFAULT "CSV"
#define NQUOTE 0
return (rval = ind); /* number of fields */
}
+#endif
int
csv_builtin (WORD_LIST *list)
{
int opt, rval;
+#if defined (ARRAY_VARS)
char *array_name, *csvstring;
SHELL_VAR *v;
opt = csvsplit (v, csvstring, ",");
/* Maybe do something with OPT here, it's the number of fields */
+#else
+ builtin_error ("arrays not available");
+ rval = EXECUTION_FAILURE;
+#endif
return (rval);
}
if (v)
{
ind = 0;
+#if defined (ARRAY_VARS)
bind_array_element (v, ind, buf, 0);
+#endif
ind++;
}
else
if (v)
{
ind = 0;
+#if defined (ARRAY_VARS)
bind_array_element (v, ind, buf, 0);
+#endif
ind++;
}
else
return ind;
if (v)
{
+#if defined (ARRAY_VARS)
bind_array_element (v, ind, line, 0);
+#endif
ind++;
}
else
{
if (bmap[b] == 0)
continue;
+#if defined (ARRAY_VARS)
if (v)
{
bind_array_element (v, ind, fields[b], 0);
ind++;
}
else
+#endif
{
if (i == 0)
putchar (ops->delim);
switch (opt)
{
case 'a':
+#if defined (ARRAY_VARS)
array_name = list_optarg;
break;
+#else
+ builtin_error ("arrays not available");
+ return (EX_USAGE);
+#endif
case 'b':
cutflags |= BFLAG;
list_arg = list_optarg;
return (EXECUTION_FAILURE);
}
+#if defined (ARRAY_VARS)
if (array_name)
{
v = builtin_find_indexed_array (array_name, 1);
return (EXECUTION_FAILURE);
}
}
+#endif
op.flags = cutflags;
op.delim = delim;
#include "loadables.h"
+#if defined (ARRAY_VARS)
+
#define DSV_ARRAY_DEFAULT "DSV"
#define NQUOTE 0
return (rval = ind); /* number of fields */
}
+#endif
int
dsv_builtin (WORD_LIST *list)
{
int opt, rval, flags;
+#if defined (ARRAY_VARS)
char *array_name, *dsvstring, *delims;
SHELL_VAR *v;
opt = dsvsplit (v, dsvstring, delims, flags);
/* Maybe do something with OPT here, it's the number of fields */
+#else
+ builtin_error ("arrays not available");
+ rval = EXECUTION_FAILURE;
+#endif
return (rval);
}
extern int errno;
#endif
+#if defined (ARRAY_VARS)
+
#define KV_ARRAY_DEFAULT "KV"
/* Split LINE into a key and value, with the delimiter between the key and
QUIT;
return nr;
}
+#endif
int
kv_builtin (WORD_LIST *list)
{
+#if defined (ARRAY_VARS)
int opt, rval, free_delims;
char *array_name, *delims, *rs;
SHELL_VAR *v;
if (free_delims)
free (delims); /* getifs returns allocated memory */
return (rval > 0 ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
+#else
+ builtin_error ("arrays not available");
+ return (EXECUTION_FAILURE);
+#endif
}
/* Called when builtin is enabled and loaded from the shared object. If this
builtin_error("%s: %s", p, strerror(errno));
continue;
}
+#if defined (ARRAY_VARS)
if (aflag) {
bind_array_element (v, ind, r, 0);
ind++;
}
+#endif
if (qflag == 0) {
if (vflag)
printf ("%s -> ", p);
extern int errno;
#endif
+#if defined (ARRAY_VARS)
+
#define ST_NAME 0
#define ST_DEV 1
#define ST_INO 2
}
return 0;
}
+#endif
int
stat_builtin (WORD_LIST *list)
{
+#if defined (ARRAY_VARS)
int opt, flags;
char *aname, *fname, *timefmt;
struct stat st;
}
return (EXECUTION_SUCCESS);
+#else
+ builtin_error ("arrays not available");
+ return (EXECUTION_FAILURE);
+#endif
}
/* An array of strings forming the `long' documentation for a builtin xxx,
QUIT;
#if defined (JOB_CONTROL)
- if (command->value.Connection->connector == ';' && job_control && interactive)
+ if (command->value.Connection->connector == ';' && job_control && interactive && posixly_correct == 0)
notify_and_cleanup ();
#endif
optimize_connection_fork (command); /* XXX */
static int
execute_null_command (REDIRECT *redirects, int pipe_in, int pipe_out, int async)
{
- int r;
+ int r, code;
int forcefork, fork_flags;
REDIRECT *rd;
if (pipe_in != NO_PIPE || pipe_out != NO_PIPE)
subshell_environment |= SUBSHELL_PIPE;
+ code = setjmp_nosigs (top_level);
+ if (code)
+ exit (EXECUTION_FAILURE);
+
if (do_redirections (redirects, RX_ACTIVE) == 0)
exit (EXECUTION_SUCCESS);
else
if (jobs_list_frozen > 0)
return;
- if (want_job_notifications || interactive || interactive_shell == 0 || sourcelevel)
+ if (want_job_notifications || interactive || interactive_shell == 0)
notify_of_job_status ();
+ else if (interactive_shell && sourcelevel && shell_compatibility_level <= 52)
+ notify_of_job_status (); /* XXX - was not dependent on BASH_COMPAT */
if (jobs_list_frozen < 0)
return; /* status changes only */
else if (word_token_alist[i].token == '}' && open_brace_count) \
open_brace_count--; \
\
- if (last_read_token == IF || last_read_token == WHILE || last_read_token == UNTIL) \
- set_word_top (last_read_token); \
+ set_word_top (word_token_alist[i].token); \
\
if (posixly_correct) \
parser_state &= ~PST_ALEXPNEXT; \
parser_state &= ~PST_ASSIGNOK;
parser_state &= ~PST_CMDBLTIN;
- if (last_read_token == IF || last_read_token == WHILE || last_read_token == UNTIL)
- set_word_top (last_read_token);
-
return (character);
}
/* case pattern lists may be preceded by an optional left paren. If
we're not trying to parse a case pattern list, the left paren
indicates a subshell. */
+ /* XXX - check for last_read_token != WORD before setting PST_SUBSHELL? */
if MBTEST(character == '(' && (parser_state & PST_CASEPAT) == 0) /* ) */
parser_state |= PST_SUBSHELL;
/*(*/
#if defined (ARITH_FOR_COMMAND)
if (last_read_token == FOR)
{
- set_word_top (last_read_token);
arith_for_lineno = line_number;
cmdtyp = parse_arith_cmd (&wval, 0);
if (cmdtyp == 1)
{
sline = line_number;
- if (last_read_token == IF || last_read_token == WHILE || last_read_token == UNTIL)
- set_word_top (last_read_token);
cmdtyp = parse_arith_cmd (&wval, 0);
if (cmdtyp == 1) /* arithmetic command */
{
expecting_in_token++;
break;
}
- set_word_top (last_read_token);
return (result);
}
array: 1
sh: line 1: export: `AA[4]': not a valid identifier
sh: line 1: readonly: `AA[4]': not a valid identifier
+bash: -c: line 5: syntax error: unexpected end of file from command on line 1
+bash: -c: line 3: syntax error: unexpected end of file from command on line 1
+bash: -c: line 4: syntax error: unexpected end of file from command on line 1
+bash: -c: line 5: syntax error: unexpected end of file from command on line 1
+bash: -c: line 7: syntax error: unexpected end of file from command on line 1
bash: line 1: return: can only `return' from a function or sourced script
after return
bash: line 1: return: can only `return' from a function or sourced script
sh: line 1: /nosuchfile: No such file or directory
sh: line 1: trap: SIGNOSIG: invalid signal specification
after trap
-./errors.tests: line 393: `!!': not a valid identifier
+./errors.tests: line 396: `!!': not a valid identifier
# invalid identifiers to readonly/export
${THIS_SH} ./errors11.sub
+# EOF when parsing compound commands
+${THIS_SH} ./errors12.sub
+
${THIS_SH} -c 'return ; echo after return' bash
${THIS_SH} -o posix -c 'return ; echo after return' bash
--- /dev/null
+: ${THIS_SH:=./bash}
+
+# various error messages about incomplete compound commands
+
+${THIS_SH} -c 'if
+ true; true
+then
+ echo foo bar' bash
+
+${THIS_SH} -c 'while false; do
+ echo true' bash
+
+${THIS_SH} -c 'until false
+do
+ echo false
+' bash
+
+${THIS_SH} -c 'for f
+in 1 2 3
+do
+ : ; :' bash
+
+${THIS_SH} -c 'case foo in
+bar) if false
+ then
+ true
+ fi
+ ;;
+' bash
+
+# this tripped up ubsan
+x()
+{
+ case y in
+ z)
+ if (! false); then
+ foo=bar
+ fi
+ ;;
+ esac
+}
+