more changes for here-docs and $'...'; command optimization updates

This commit is contained in:
Chet Ramey
2022-01-31 09:53:03 -05:00
parent 6e1ab9a367
commit b325b0e96b
20 changed files with 423 additions and 56 deletions
+39 -1
View File
@@ -3009,10 +3009,48 @@ subst.c
read this new ${...} string
- extract_heredoc_dolbrace_string: new function, variant of
extract_dollar_brace_string, to process the WORD in ${PARAM OP WORD}
while processing here-document data. It's complicated by the
while expanding lines of here-document data. It's complicated by the
requirement to add to the result string as we go along, since we
need to change the contents of the input string with ansi expansion
or locale translation.
- string_extract_single_quoted: take a new third argument: ALLOWESC.
This allows backslash to escape an embedded single quote, needed by
extract_heredoc_dolbrace_string to process $'...'; changed callers
1/25
----
parse.y
- parse_matched_pair: ansi-expand $'...' in WORD for ${PARAM OP WORD}
and single-quote the result if dolbrace_state == DOLBRACE_QUOTE
(posix pattern removal operators) even if extended_quote == 0
subst.c
- extract_heredoc_dolbrace_string: add logic to align with parse.y:
parse_matched_pair and its $'...' expansion, including handling
extended_quote
1/27
----
builtins/evalstring.c
- should_optimize_fork: broke conditions for optimizing away the fork
for a simple command out of optimize_fork into new function, call
from should_suppress_fork and optimize_subshell_command. Call from
optimize_fork if (subshell_environment & SUBSHELL_PAREN), relying
on fact that CMD_TRY_OPTIMIZING is only set in a couple of specific
conditions
- optimize_fork: call should_suppress_fork only if startup_state == 2;
it does the extra checks for that specific case
- optimize_fork: call should_optimize_fork if we're in a (list)
subshell (subshell_environment & SUBSHELL_PAREN)
- optimize_subshell_command: set CMD_TRY_OPTIMIZING on the right side
of a `&&', `||', or `;' list as long as it's a simple command so
we can check with optimize_fork() when it's time to execute it
execute_cmd.c
- execute_in_subshell: call optimize_subshell_command for (list)
subshells to either set CMD_NO_FORK for simple commands or set
CMD_TRY_OPTIMIZING for likely candidates for later optimization
builtins/common.h,builtins/evalstring.c
- optimize_fork: renamed to optimize_connection_fork; changed callers
+1
View File
@@ -454,6 +454,7 @@ lib/sh/strtoul.c f
lib/sh/strtoull.c f
lib/sh/strtoumax.c f
lib/sh/strtrans.c f
lib/sh/strvis.c f
lib/sh/timers.c f
lib/sh/times.c f
lib/sh/timeval.c f
+1 -1
View File
@@ -239,7 +239,7 @@ SHLIB_SOURCE = ${SH_LIBSRC}/clktck.c ${SH_LIBSRC}/getcwd.c \
${SH_LIBSRC}/wcswidth.c ${SH_LIBSRC}/wcsnwidth.c \
${SH_LIBSRC}/shmbchar.c ${SH_LIBSRC}/utf8.c \
${SH_LIBSRC}/random.c ${SH_LIBSRC}/gettimeofday.c \
${SH_LIBSRC}/timers.c
${SH_LIBSRC}/timers.c ${SH_LIBSRC}/strvis.c
SHLIB_LIB = -lsh
SHLIB_LIBNAME = libsh.a
+2 -2
View File
@@ -1,6 +1,6 @@
/* common.h -- extern declarations for functions defined in common.c. */
/* Copyright (C) 1993-2021 Free Software Foundation, Inc.
/* Copyright (C) 1993-2022 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -217,7 +217,7 @@ extern int parse_string PARAMS((char *, const char *, int, COMMAND **, char **))
extern int should_suppress_fork PARAMS((COMMAND *));
extern int can_optimize_connection PARAMS((COMMAND *));
extern int can_optimize_cat_file PARAMS((COMMAND *));
extern void optimize_fork PARAMS((COMMAND *));
extern void optimize_connection_fork PARAMS((COMMAND *));
extern void optimize_subshell_command PARAMS((COMMAND *));
extern void optimize_shell_function PARAMS((COMMAND *));
+31 -21
View File
@@ -1,6 +1,6 @@
/* evalstring.c - evaluate a string as one or more shell commands. */
/* Copyright (C) 1996-2021 Free Software Foundation, Inc.
/* Copyright (C) 1996-2022 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -84,6 +84,24 @@ restore_lastcom (x)
the_printed_command_except_trap = x;
}
int
should_optimize_fork (command, subshell)
COMMAND *command;
int subshell;
{
return (running_trap == 0 &&
command->type == cm_simple &&
signal_is_trapped (EXIT_TRAP) == 0 &&
signal_is_trapped (ERROR_TRAP) == 0 &&
any_signals_trapped () < 0 &&
(subshell || (command->redirects == 0 && command->value.Simple->redirects == 0)) &&
((command->flags & CMD_TIME_PIPELINE) == 0) &&
((command->flags & CMD_INVERT_RETURN) == 0));
}
/* This has extra tests to account for STARTUP_STATE == 2, which is for
-c command but has been extended to command and process substitution
(basically any time you call parse_and_execute in a subshell). */
int
should_suppress_fork (command)
COMMAND *command;
@@ -94,14 +112,7 @@ should_suppress_fork (command)
return (startup_state == 2 && parse_and_execute_level == 1 &&
*bash_input.location.string == '\0' &&
parser_expanding_alias () == 0 &&
running_trap == 0 &&
command->type == cm_simple &&
signal_is_trapped (EXIT_TRAP) == 0 &&
signal_is_trapped (ERROR_TRAP) == 0 &&
any_signals_trapped () < 0 &&
(subshell || (command->redirects == 0 && command->value.Simple->redirects == 0)) &&
((command->flags & CMD_TIME_PIPELINE) == 0) &&
((command->flags & CMD_INVERT_RETURN) == 0));
should_optimize_fork (command, subshell));
}
int
@@ -115,13 +126,14 @@ can_optimize_connection (command)
}
void
optimize_fork (command)
optimize_connection_fork (command)
COMMAND *command;
{
if (command->type == cm_connection &&
(command->value.Connection->connector == AND_AND || command->value.Connection->connector == OR_OR || command->value.Connection->connector == ';') &&
(command->value.Connection->second->flags & CMD_TRY_OPTIMIZING) &&
should_suppress_fork (command->value.Connection->second))
((startup_state == 2 && should_suppress_fork (command->value.Connection->second)) ||
((subshell_environment & SUBSHELL_PAREN) && should_optimize_fork (command->value.Connection->second, 0))))
{
command->value.Connection->second->flags |= CMD_NO_FORK;
command->value.Connection->second->value.Simple->flags |= CMD_NO_FORK;
@@ -132,21 +144,19 @@ void
optimize_subshell_command (command)
COMMAND *command;
{
if (running_trap == 0 &&
command->type == cm_simple &&
signal_is_trapped (EXIT_TRAP) == 0 &&
signal_is_trapped (ERROR_TRAP) == 0 &&
any_signals_trapped () < 0 &&
command->redirects == 0 && command->value.Simple->redirects == 0 &&
((command->flags & CMD_TIME_PIPELINE) == 0) &&
((command->flags & CMD_INVERT_RETURN) == 0))
if (should_optimize_fork (command, 0))
{
command->flags |= CMD_NO_FORK;
command->value.Simple->flags |= CMD_NO_FORK;
}
else if (command->type == cm_connection &&
(command->value.Connection->connector == AND_AND || command->value.Connection->connector == OR_OR))
optimize_subshell_command (command->value.Connection->second);
(command->value.Connection->connector == AND_AND || command->value.Connection->connector == OR_OR || command->value.Connection->connector == ';') &&
command->value.Connection->second->type == cm_simple &&
parser_expanding_alias () == 0)
{
command->value.Connection->second->flags |= CMD_TRY_OPTIMIZING;
command->value.Connection->second->value.Simple->flags |= CMD_TRY_OPTIMIZING;
}
}
void
+7 -7
View File
@@ -1,6 +1,6 @@
/* execute_cmd.c -- Execute a COMMAND structure. */
/* Copyright (C) 1987-2021 Free Software Foundation, Inc.
/* Copyright (C) 1987-2022 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -1650,12 +1650,12 @@ execute_in_subshell (command, asynchronous, pipe_in, pipe_out, fds_to_close)
default_buffered_input = -1;
#endif
#if 0
/* We can't optimize if one of the commands executed by the subshell sets
an exit trap. */
/* We can't optimize away forks if one of the commands executed by the
subshell sets an exit trap, so we set CMD_NO_FORK for simple commands
and set CMD_TRY_OPTIMIZING for simple commands on the right side of an
and-or or `;' list to test for optimizing forks when they are executed. */
if (user_subshell && command->type == cm_subshell)
optimize_subshell_command (command->value.Subshell->command);
#endif
/* Do redirections, then dispose of them before recursive call. */
if (command->redirects)
@@ -2753,7 +2753,7 @@ execute_connection (command, asynchronous, pipe_in, pipe_out, fds_to_close)
#endif
QUIT;
optimize_fork (command); /* XXX */
optimize_connection_fork (command); /* XXX */
exec_result = execute_command_internal (command->value.Connection->second,
asynchronous, pipe_in, pipe_out,
fds_to_close);
@@ -2826,7 +2826,7 @@ execute_connection (command, asynchronous, pipe_in, pipe_out, fds_to_close)
((command->value.Connection->connector == OR_OR) &&
(exec_result != EXECUTION_SUCCESS)))
{
optimize_fork (command);
optimize_connection_fork (command);
second = command->value.Connection->second;
if (ignore_return && second)
+4
View File
@@ -471,6 +471,10 @@ extern char *ansic_quote PARAMS((char *, int, int *));
extern int ansic_shouldquote PARAMS((const char *));
extern char *ansiexpand PARAMS((char *, int, int, int *));
/* declarations for functions defined in lib/sh/strvis.c */
extern int charvis PARAMS((const char *, size_t *, char *, size_t *));
extern char *sh_strvis PARAMS((const char *));
/* declarations for functions defined in lib/sh/timeval.c. No prototypes
so we don't have to count on having a definition of struct timeval in
scope when this file is included. */
+1 -1
View File
@@ -103,7 +103,7 @@
#endif
#ifndef UNCTRL
/* control char to letter -- ASCII */
# define UNCTRL(x) (TOUPPER(x) ^ 0x40)
# define UNCTRL(x) (TOUPPER(x ^ 0x40))
#endif
#endif /* _SH_CHARTYPES_H */
+7 -4
View File
@@ -1184,10 +1184,13 @@ Returns 0 if the timeout is set successfully.
@deftypefun int rl_timeout_remaining (unsigned int *secs, unsigned int *usecs)
Return the number of seconds and microseconds remaining in the current
timeout duration in @code{*secs} and @code{*usecs}, respectively.
Returns -1 on error or when there is no timeout set, 0 when the timeout has
expired (leaving @code{*secs} and @code{*usecs} unchanged), and 1 if the
timeout has not expired. If @code{secs} and @code{usecs} are @code{NULL},
timeout duration in @var{*secs} and @var{*usecs}, respectively.
Both @var{*secs} and @var{*usecs} must be non-NULL to return any values.
The return value is -1 on error or when there is no timeout set,
0 when the timeout has expired (leaving @var{*secs} and @var{*usecs}
unchanged),
and 1 if the timeout has not expired.
If either of @var{secs} and @var{usecs} is @code{NULL},
the return value indicates whether the timeout has expired.
@end deftypefun
+1 -1
View File
@@ -44,7 +44,7 @@ typedef char *histdata_t;
/* Let's not step on anyone else's define for now, since we don't use this yet. */
#ifndef HS_HISTORY_VERSION
# define HS_HISTORY_VERSION 0x0801 /* History 8.1 */
# define HS_HISTORY_VERSION 0x0802 /* History 8.2 */
#endif
/* The structure used to store a history entry. */
+2 -2
View File
@@ -39,9 +39,9 @@ extern "C" {
#endif
/* Hex-encoded Readline version number. */
#define RL_READLINE_VERSION 0x0801 /* Readline 8.1 */
#define RL_READLINE_VERSION 0x0802 /* Readline 8.2 */
#define RL_VERSION_MAJOR 8
#define RL_VERSION_MINOR 1
#define RL_VERSION_MINOR 2
/* Readline data structures. */
+10 -3
View File
@@ -2,7 +2,7 @@
# Makefile for the Bash library
#
#
# Copyright (C) 1998-2020 Free Software Foundation, Inc.
# Copyright (C) 1998-2022 Free Software Foundation, Inc.
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -94,7 +94,7 @@ CSOURCES = clktck.c clock.c getcwd.c getenv.c oslib.c setlinebuf.c \
wcsdup.c fpurge.c zgetline.c mbscmp.c uconvert.c ufuncs.c \
casemod.c dprintf.c input_avail.c mbscasecmp.c fnxform.c \
strchrnul.c unicode.c wcswidth.c wcsnwidth.c shmbchar.c strdup.c \
utf8.c random.c gettimeofday.c timers.c
strvis.c utf8.c random.c gettimeofday.c timers.c
# The header files for this library.
HSOURCES =
@@ -108,7 +108,7 @@ OBJECTS = clktck.o clock.o getenv.o oslib.o setlinebuf.o strnlen.o \
strtrans.o snprintf.o mailstat.o fmtulong.o \
fmtullong.o fmtumax.o zcatfd.o zmapfd.o winsize.o wcsdup.o \
fpurge.o zgetline.o mbscmp.o uconvert.o ufuncs.o casemod.o \
input_avail.o mbscasecmp.o fnxform.o unicode.o shmbchar.o \
input_avail.o mbscasecmp.o fnxform.o unicode.o shmbchar.o strvis.o \
utf8.o random.o gettimeofday.o timers.o wcsnwidth.o ${LIBOBJS}
SUPPORT = Makefile
@@ -198,6 +198,7 @@ strtoul.o: strtoul.c
strtoull.o: strtoull.c
strtoumax.o: strtoumax.c
strtrans.o: strtrans.c
strvis.o: strvis.c
timers.o: timers.c
times.o: times.c
timeval.o: timeval.c
@@ -279,6 +280,7 @@ strtoul.o: ${BUILD_DIR}/config.h
strtoull.o: ${BUILD_DIR}/config.h
strtoumax.o: ${BUILD_DIR}/config.h
strtrans.o: ${BUILD_DIR}/config.h
strvis.o: ${BUILD_DIR}/config.h
timers.o: ${BUILD_DIR}/config.h
times.o: ${BUILD_DIR}/config.h
timeval.o: ${BUILD_DIR}/config.h
@@ -512,6 +514,11 @@ strtrans.o: ${BUILD_DIR}/pathnames.h ${topdir}/externs.h
strtrans.o: ${BASHINCDIR}/shmbutil.h ${BASHINCDIR}/shmbchar.h
#strtrans.o: ${BUILD_DIR}/version.h
strvis.o: ${topdir}/bashansi.h
strvis.o: ${BASHINCDIR}/ansi_stdlib.h ${BASHINCDIR}/chartypes.h
strvis.o: ${BASHINCDIR}/shmbutil.h ${BASHINCDIR}/shmbchar.h
strvis.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
times.o: ${BASHINCDIR}/systimes.h
times.o: ${BASHINCDIR}/posixtime.h
-1
View File
@@ -17,7 +17,6 @@
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>
+145
View File
@@ -0,0 +1,145 @@
/* strvis.c - make unsafe graphical characters in a string visible. */
/* Copyright (C) 2022 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/>.
*/
/* This is a stripped-down version suitable for the shell's use. */
#include <config.h>
#include <unistd.h>
#include "bashansi.h"
#include <stdio.h>
#include "chartypes.h"
#include "bashintl.h"
#include "shmbutil.h"
#define SAFECHAR(c) ((c) == ' ' || (c) == '\t')
#ifndef RUBOUT
#define RUBOUT 0x7f
#endif
#ifndef CTRL_CHAR
#define CTRL_CHAR(c) ((c) < 0x20)
#endif
#ifndef META_CHAR
#define META_CHAR(c) ((c) > 0x7f && (c) <= UCHAR_MAX)
#endif
#ifndef UNCTRL
#define UNCTRL(c) (TOUPPER ((c) | 0x40))
#endif
#ifndef UNMETA
#define UNMETA(c) ((c) & 0x7f)
#endif
static int
charvis (s, sindp, ret, rindp)
const char *s;
size_t *sindp;
char *ret;
size_t *rindp;
{
unsigned char c;
size_t si, ri;
const char *send;
DECLARE_MBSTATE;
si = *sindp;
ri = *rindp;
c = s[*sindp];
send = (locale_mb_cur_max > 1) ? s + strlen (s) : 0;
if (SAFECHAR (c))
{
ret[ri++] = c;
si++;
}
else if (c == RUBOUT)
{
ret[ri++] = '^';
ret[ri++] = '?';
si++;
}
else if (CTRL_CHAR (c))
{
ret[ri++] = '^';
ret[ri++] = UNCTRL (c);
si++;
}
else if (locale_mb_cur_max > 1)
COPY_CHAR_I (ret, ri, s, send, si);
else if (META_CHAR (c))
{
ret[ri++] = 'M';
ret[ri++] = '-';
ret[ri++] = UNMETA (c);
si++;
}
else
ret[ri++] = s[si++];
*sindp = si;
*rindp = ri;
return si;
}
/* Return a new string with `unsafe' non-graphical characters in S rendered
in a visible way. */
char *
sh_strvis (string)
const char *string;
{
size_t slen, sind;
char *ret;
size_t retind, retsize;
unsigned char c;
DECLARE_MBSTATE;
if (string == 0)
return 0;
if (*string == '\0')
{
if ((ret = (char *)malloc (1)) == 0)
return 0;
ret[0] = '\0';
return ret;
}
slen = strlen (string);
retsize = 3 * slen + 1;
ret = (char *)malloc (retsize);
if (ret == 0)
return 0;
retind = 0;
sind = 0;
while (string[sind])
sind = charvis (string, &sind, ret, &retind);
ret[retind] = '\0';
return ret;
}
+12 -2
View File
@@ -3805,7 +3805,7 @@ parse_matched_pair (qc, open, close, lenp, flags)
pop_delimiter (dstack);
CHECK_NESTRET_ERROR ();
if MBTEST((tflags & LEX_WASDOL) && ch == '\'' && (extended_quote || (rflags & P_DQUOTE) == 0))
if MBTEST((tflags & LEX_WASDOL) && ch == '\'' && (extended_quote || (rflags & P_DQUOTE) == 0 || dolbrace_state == DOLBRACE_QUOTE || dolbrace_state == DOLBRACE_QUOTE2))
{
/* Translate $'...' here. */
/* PST_NOEXPAND */
@@ -3817,12 +3817,22 @@ parse_matched_pair (qc, open, close, lenp, flags)
make sure we single-quote the results of the ansi
expansion because quote removal should remove them later */
/* FLAG POSIX INTERP 221 */
if ((shell_compatibility_level > 42) && (rflags & P_DQUOTE) && (dolbrace_state == DOLBRACE_QUOTE2) && (flags & P_DOLBRACE))
if ((shell_compatibility_level > 42) && (rflags & P_DQUOTE) && (dolbrace_state == DOLBRACE_QUOTE2 || dolbrace_state == DOLBRACE_QUOTE) && (flags & P_DOLBRACE))
{
nestret = sh_single_quote (ttrans);
free (ttrans);
nestlen = strlen (nestret);
}
#if 0 /* TAG:bash-5.3 */
/* This single-quotes PARAM in ${PARAM OP WORD} when PARAM
contains a $'...' even when extended_quote is set. */
else if ((rflags & P_DQUOTE) && (dolbrace_state == DOLBRACE_PARAM) && (flags & P_DOLBRACE))
{
nestret = sh_single_quote (ttrans);
free (ttrans);
nestlen = strlen (nestret);
}
#endif
else if ((rflags & P_DQUOTE) == 0)
{
nestret = sh_single_quote (ttrans);
+26 -5
View File
@@ -195,6 +195,7 @@ int patsub_replacement = 1;
extern struct fd_bitmap *current_fds_to_close;
extern int wordexp_only;
extern int singlequote_translations;
extern int extended_quote;
#if defined (JOB_CONTROL) && defined (PROCESS_SUBSTITUTION)
extern PROCESS *last_procsub_child;
@@ -1523,7 +1524,9 @@ extract_delimited_string (string, sindex, opener, alt_opener, closer, flags)
path doesn't. It's separate because we don't want to mess with the fast
common path. We already know we're going to allocate and return a new
string and quoted == Q_HERE_DOCUMENT. We might be able to cut it down
some more, but extracting strings and adding them as we go adds complexity. */
some more, but extracting strings and adding them as we go adds complexity.
This needs to match the logic in parse.y:parse_matched_pair so we get
consistent behavior between here-documents and double-quoted strings. */
static char *
extract_heredoc_dolbrace_string (string, sindex, quoted, flags)
char *string;
@@ -1574,6 +1577,15 @@ extract_heredoc_dolbrace_string (string, sindex, quoted, flags)
char *ttrans;
int ttranslen;
if ((posixly_correct || extended_quote == 0) && dolbrace_state != DOLBRACE_QUOTE && dolbrace_state != DOLBRACE_QUOTE2)
{
RESIZE_MALLOCED_BUFFER (result, result_index, 3, result_size, 64);
result[result_index++] = '$';
result[result_index++] = '\'';
i += 2;
continue;
}
si = i + 2;
t = string_extract_single_quoted (string, &si, 1); /* XXX */
CHECK_STRING_OVERRUN (i, si, slen, c);
@@ -1583,9 +1595,18 @@ extract_heredoc_dolbrace_string (string, sindex, quoted, flags)
free (t);
/* needed to correctly quote any embedded single quotes. */
t = sh_single_quote (ttrans);
tlen = strlen (t);
free (ttrans);
if (dolbrace_state == DOLBRACE_QUOTE || dolbrace_state == DOLBRACE_QUOTE2)
{
t = sh_single_quote (ttrans);
tlen = strlen (t);
free (ttrans);
}
else if (extended_quote) /* dolbrace_state == DOLBRACE_PARAM */
{
/* This matches what parse.y:parse_matched_pair() does */
t = ttrans;
tlen = strlen (t);
}
RESIZE_MALLOCED_BUFFER (result, result_index, tlen + 1, result_size, 64);
strncpy (result + result_index, t, tlen);
@@ -1629,7 +1650,7 @@ extract_heredoc_dolbrace_string (string, sindex, quoted, flags)
result[result_index++] = c;
result[result_index++] = string[i+1];
i += 2;
if (dolbrace_state == DOLBRACE_QUOTE || dolbrace_state == DOLBRACE_WORD)
if (dolbrace_state == DOLBRACE_QUOTE || dolbrace_state == DOLBRACE_QUOTE2 || dolbrace_state == DOLBRACE_WORD)
dolbrace_state = DOLBRACE_PARAM;
continue;
}
+28
View File
@@ -142,3 +142,31 @@ w
x
y
z
=====
WORKS
done
WORKS
a
b
c
d
a
b
c
d
e
A
B
c
d
c
d
e
x
y
z
WORKS
w
x
y
z
+17
View File
@@ -45,3 +45,20 @@ $THIS_SH -c '$binecho c && $binecho d && echo e'
$THIS_SH -c 'trap "echo WORKS" EXIT ; $binecho x ; $binecho y ; $binecho z'
${THIS_SH} -c 'echo w ; { echo x ; $binecho y; }; $binecho z'
echo =====
( trap "echo WORKS && rm $TMPDIR/x$$" EXIT && touch $TMPDIR/x$$ )
( trap "echo WORKS && rm $TMPDIR/x$$" EXIT && touch $TMPDIR/x$$ ; $binecho done )
( echo a && { $binecho b && $binecho c ; } && echo d )
( echo a && { $binecho b && $binecho c ; } && echo d ; $binecho e )
( echo A && $binecho B )
( $binecho c && echo d )
( $binecho c && $binecho d && echo e )
( trap "echo WORKS" EXIT ; $binecho x ; $binecho y ; $binecho z )
( echo w ; { echo x ; $binecho y; }; $binecho z )
+23 -2
View File
@@ -275,10 +275,31 @@ argv[2] = <b>
[ abc def ghi jkl / abc def ghi jkl ]
[ abc def ghi jkl ]
[ abc def ghi jkl / abc def ghi jkl / abc def ghi jkl ]
5: OK
1: OK
2: $'not'
3: OK
4: OK
5: tOK
OK
OK
5: $'not\ttoo\nbad'
$'not'
OK
tOK
6: $'not\ttoo\nbad'
OKa ' b
OKa ' b
7: OK
8: OKa ' b
9: OKa " b
10: OKa " b
tOK
tOK
tOK
tOK
./posixexp7.sub: line 69: ${'x1'%'t'}: bad substitution
./posixexp7.sub: line 70: ${'x1'%'t'}: bad substitution
./posixexp7.sub: line 73: ${'x1'%'t'}: bad substitution
./posixexp7.sub: line 74: ${'x1'%'t'}: bad substitution
"A"
A
argv[1] = <"A">
+66 -3
View File
@@ -1,13 +1,76 @@
# This program 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.
#
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
#
# test the effect of quotes on the WORD in the posix pattern removal operators
# a here document does not behave the same as double quotes
#
x=notOK
x1=not
cat <<EOF
5: ${x#$'not'}
1: ${x#$'not'}
2: $'not'
3: ${x#"not"}
4: ${x#'not'}
5: ${x#${x1%'t'}}
EOF
echo "${x#'not'}"
echo "${x#$'not'}"
echo "$'not'"
echo "${x#"not"}"
echo "${x#${x1%'t'}}"
cat <<EOF
5: $'not\ttoo\nbad'
6: $'not\ttoo\nbad'
EOF
x=OK$'a\t\'\tb'
echo OK$'a\t\'\tb'
echo "$x"
cat <<EOF
7: ${x%$'a\t\'\tb'}
8: ${x#$'a\t\'\tb'}
EOF
x=OK'a " b'
cat <<EOF
9: ${x#'a " b'}
10: ${x#$'a " b'}
EOF
x=notOK
x1=not
# extquote makes these work
echo "${x#${$'x1'%$'t'}}"
cat <<EOF
${x#${$'x1'%$'t'}}
EOF
echo "${x#${$'x1'%'t'}}"
cat <<EOF
${x#${$'x1'%'t'}}
EOF
# syntax errors
echo "${x#${'x1'%'t'}}"
cat <<EOF
${x#${'x1'%'t'}}
EOF
echo "${x#${'x1'%$'t'}}"
cat <<EOF
${x#${'x1'%$'t'}}
EOF