mirror of
https://https.git.savannah.gnu.org/git/bash.git
synced 2026-06-27 07:43:07 +02:00
commit bash-20180112 snapshot
This commit is contained in:
@@ -14800,3 +14800,51 @@ subst.c
|
||||
'G' to the options list if W_CHKLOCAL is set in the word's flags.
|
||||
This makes builtins like `readonly' that modify local variables in
|
||||
a function behave the same for scalar and array variables
|
||||
|
||||
1/11
|
||||
----
|
||||
parse.y
|
||||
- shell_getc: move code that decides whether to append a space to an
|
||||
alias expansion here from mk_alexpansion, so we can inhibit adding
|
||||
a space if we're currently parsing a single or double quoted string
|
||||
|
||||
1/12
|
||||
----
|
||||
|
||||
parse.y
|
||||
- clear_string_list_expander: take a pointer to an alias that's about
|
||||
to be freed and make sure there aren't any pointers to it in the
|
||||
list of pushed strings. If there are, zero it out in the pushed
|
||||
string list to avoid referencing freed memory in pop_string()
|
||||
|
||||
alias.c
|
||||
- free_alias_data: if an alias being freed is currently being expanded,
|
||||
call clear_string_list_expander to remove references to it from the
|
||||
list of pushed strings
|
||||
|
||||
1/14
|
||||
----
|
||||
pcomplib.c
|
||||
- progcomp_search: add code to look up an alias for the CMD argument
|
||||
and return the completions for the first word of that alias if one
|
||||
is found. Just a start at completing aliases, a much-requested
|
||||
feature
|
||||
|
||||
pcomplete.h
|
||||
- COPT_LASTUSER: last flag value used by user-settable completion
|
||||
options
|
||||
- PCOMP_RETRYFAIL, PCOMP_NOTFOUND: new #defines, possible return values
|
||||
from programmable_completions in FOUNDP argument. Moved RETRYFAIL
|
||||
define here from pcomplete.c to avoid collisions with user-settable
|
||||
option values (COPT_*)
|
||||
|
||||
1/15
|
||||
----
|
||||
pcomplete.c
|
||||
- programmable_completions: if we don't find any completions for a
|
||||
command, and RETRY is 0, see if the command is a defined alias,
|
||||
expand it, and try to expand the first word of the value as a
|
||||
command, and find any programmable completions for it. Here right
|
||||
now, could be moved to attempt_shell_completion later if we need
|
||||
to do more analysis of the expanded line. We'll see how it works
|
||||
in practice.
|
||||
|
||||
@@ -820,6 +820,7 @@ tests/alias.tests f
|
||||
tests/alias1.sub f
|
||||
tests/alias2.sub f
|
||||
tests/alias3.sub f
|
||||
tests/alias4.sub f
|
||||
tests/alias.right f
|
||||
tests/appendop.tests f
|
||||
tests/appendop1.sub f
|
||||
|
||||
@@ -158,6 +158,10 @@ free_alias_data (data)
|
||||
register alias_t *a;
|
||||
|
||||
a = (alias_t *)data;
|
||||
|
||||
if (a->flags & AL_BEINGEXPANDED)
|
||||
clear_string_list_expander (a); /* call back to the parser */
|
||||
|
||||
free (a->value);
|
||||
free (a->name);
|
||||
free (data);
|
||||
|
||||
@@ -67,4 +67,7 @@ extern char *alias_expand_word __P((char *));
|
||||
/* Return a new line, with any aliases expanded. */
|
||||
extern char *alias_expand __P((char *));
|
||||
|
||||
/* Helper definition for the parser */
|
||||
extern void clear_string_list_expander __P((alias_t *));
|
||||
|
||||
#endif /* _ALIAS_H_ */
|
||||
|
||||
@@ -681,6 +681,8 @@ compgen_builtin (list)
|
||||
COMPSPEC *cs;
|
||||
STRINGLIST *sl;
|
||||
char *word, **matches;
|
||||
char *old_line;
|
||||
int old_ind;
|
||||
|
||||
if (list == 0)
|
||||
return (EXECUTION_SUCCESS);
|
||||
@@ -721,7 +723,15 @@ compgen_builtin (list)
|
||||
cs->filterpat = STRDUP (Xarg);
|
||||
|
||||
rval = EXECUTION_FAILURE;
|
||||
|
||||
/* probably don't have to save these, just being safe */
|
||||
old_line = pcomp_line;
|
||||
old_ind = pcomp_ind;
|
||||
pcomp_line = (char *)NULL;
|
||||
pcomp_ind = 0;
|
||||
sl = gen_compspec_completions (cs, "compgen", word, 0, 0, 0);
|
||||
pcomp_line = old_line;
|
||||
pcomp_ind = old_ind;
|
||||
|
||||
/* If the compspec wants the bash default completions, temporarily
|
||||
turn off programmable completion and call the bash completion code. */
|
||||
|
||||
@@ -40,11 +40,11 @@ Options which set attributes:
|
||||
-a to make NAMEs indexed arrays (if supported)
|
||||
-A to make NAMEs associative arrays (if supported)
|
||||
-i to make NAMEs have the `integer' attribute
|
||||
-l to convert NAMEs to lower case on assignment
|
||||
-l to convert the value of each NAME to lower case on assignment
|
||||
-n make NAME a reference to the variable named by its value
|
||||
-r to make NAMEs readonly
|
||||
-t to make NAMEs have the `trace' attribute
|
||||
-u to convert NAMEs to upper case on assignment
|
||||
-u to convert the value of each NAME to upper case on assignment
|
||||
-x to make NAMEs export
|
||||
|
||||
Using `+' instead of `-' turns off the given attribute.
|
||||
|
||||
+1
-1
@@ -4373,7 +4373,7 @@ Remove a trailing @var{delim} (default newline) from each line read.
|
||||
@item -u
|
||||
Read lines from file descriptor @var{fd} instead of the standard input.
|
||||
@item -C
|
||||
Evaluate @var{callback} each time @var{quantum}P lines are read.
|
||||
Evaluate @var{callback} each time @var{quantum} lines are read.
|
||||
The @option{-c} option specifies @var{quantum}.
|
||||
@item -c
|
||||
Specify the number of lines read between each call to @var{callback}.
|
||||
|
||||
@@ -95,6 +95,8 @@ typedef void *alias_t;
|
||||
#define RE_READ_TOKEN -99
|
||||
#define NO_EXPANSION -100
|
||||
|
||||
#define END_ALIAS -2
|
||||
|
||||
#ifdef DEBUG
|
||||
# define YYDEBUG 1
|
||||
#else
|
||||
@@ -1967,6 +1969,23 @@ parser_restore_alias ()
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined (ALIAS)
|
||||
/* Before freeing AP, make sure that there aren't any cases of pointer
|
||||
aliasing that could cause us to reference freed memory later on. */
|
||||
void
|
||||
clear_string_list_expander (ap)
|
||||
alias_t *ap;
|
||||
{
|
||||
register STRING_SAVER *t;
|
||||
|
||||
for (t = pushed_string_list; t; t = t->next)
|
||||
{
|
||||
if (t->expander && t->expander == ap)
|
||||
t->expander = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
clear_shell_input_line ()
|
||||
{
|
||||
@@ -2500,6 +2519,30 @@ next_alias_char:
|
||||
parsing an alias, we have just saved one (push_string, when called by
|
||||
the parse_dparen code) In this case, just go on as well. The PSH_SOURCE
|
||||
case is handled below. */
|
||||
|
||||
/* If we're at the end of an alias expansion add a space to make sure that
|
||||
the alias remains marked as being in use while we expand its last word.
|
||||
This makes sure that pop_string doesn't mark the alias as not in use
|
||||
before the string resulting from the alias expansion is tokenized and
|
||||
checked for alias expansion, preventing recursion. At this point, the
|
||||
last character in shell_input_line is the last character of the alias
|
||||
expansion. We test that last character to determine whether or not to
|
||||
return the space that will delimit the token and postpone the pop_string.
|
||||
This set of conditions duplicates what used to be in mk_alexpansion ()
|
||||
below, with the addition that we don't add a space if we're currently
|
||||
reading a quoted string. */
|
||||
#ifndef OLD_ALIAS_HACK
|
||||
if (uc == 0 && pushed_string_list && pushed_string_list->flags != PSH_SOURCE &&
|
||||
shell_input_line_index > 0 &&
|
||||
shell_input_line[shell_input_line_index-1] != ' ' &&
|
||||
shell_input_line[shell_input_line_index-1] != '\n' &&
|
||||
shellmeta (shell_input_line[shell_input_line_index-1]) == 0 &&
|
||||
(current_delimiter (dstack) != '\'' && current_delimiter (dstack) != '"'))
|
||||
{
|
||||
return ' '; /* END_ALIAS */
|
||||
}
|
||||
#endif
|
||||
|
||||
pop_alias:
|
||||
if (uc == 0 && pushed_string_list && pushed_string_list->flags != PSH_SOURCE)
|
||||
{
|
||||
@@ -2518,10 +2561,9 @@ pop_alias:
|
||||
/* What do we do here if we're expanding an alias whose definition
|
||||
includes an escaped newline? If that's the last character in the
|
||||
alias expansion, we just pop the pushed string list (recall that
|
||||
we inhibit the appending of a space in mk_alexpansion() if newline
|
||||
is the last character). If it's not the last character, we need
|
||||
to consume the quoted newline and move to the next character in
|
||||
the expansion. */
|
||||
we inhibit the appending of a space if newline is the last
|
||||
character). If it's not the last character, we need to consume the
|
||||
quoted newline and move to the next character in the expansion. */
|
||||
#if defined (ALIAS)
|
||||
if (expanding_alias () && shell_input_line[shell_input_line_index+1] == '\0')
|
||||
{
|
||||
@@ -2829,13 +2871,15 @@ mk_alexpansion (s)
|
||||
l = strlen (s);
|
||||
r = xmalloc (l + 2);
|
||||
strcpy (r, s);
|
||||
#ifdef OLD_ALIAS_HACK
|
||||
/* If the last character in the alias is a newline, don't add a trailing
|
||||
space to the expansion. Works with shell_getc above. */
|
||||
/* Need to do something about the case where the alias expansion contains
|
||||
an unmatched quoted string, since appending this space affects the
|
||||
subsequent output. */
|
||||
if (r[l - 1] != ' ' && r[l - 1] != '\n' && shellmeta(r[l - 1]) == 0)
|
||||
if (l > 0 && r[l - 1] != ' ' && r[l - 1] != '\n' && shellmeta(r[l - 1]) == 0)
|
||||
r[l++] = ' ';
|
||||
#endif
|
||||
r[l] = '\0';
|
||||
return r;
|
||||
}
|
||||
@@ -2856,12 +2900,14 @@ alias_expand_token (tokstr)
|
||||
if (ap && (ap->flags & AL_BEINGEXPANDED))
|
||||
return (NO_EXPANSION);
|
||||
|
||||
#ifdef OLD_ALIAS_HACK
|
||||
/* mk_alexpansion puts an extra space on the end of the alias expansion,
|
||||
so the lookahead by the parser works right (the alias needs to remain
|
||||
`in use' while parsing its last word to avoid alias recursion for
|
||||
something like "alias echo=echo"). If this gets changed, make sure
|
||||
the code in shell_getc that deals with reaching the end of an
|
||||
expanded alias is changed with it. */
|
||||
#endif
|
||||
expanded = ap ? mk_alexpansion (ap->value) : (char *)NULL;
|
||||
|
||||
if (expanded)
|
||||
|
||||
+97
-13
@@ -1,6 +1,6 @@
|
||||
/* pcomplete.c - functions to generate lists of matches for programmable completion. */
|
||||
|
||||
/* Copyright (C) 1999-2012 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1999-2018 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
@@ -71,8 +71,6 @@
|
||||
#include <readline/readline.h>
|
||||
#include <readline/history.h>
|
||||
|
||||
#define PCOMP_RETRYFAIL 256
|
||||
|
||||
#ifdef STRDUP
|
||||
# undef STRDUP
|
||||
#endif
|
||||
@@ -153,6 +151,10 @@ static int progcomp_debug = 0;
|
||||
|
||||
int prog_completion_enabled = 1;
|
||||
|
||||
#ifdef ALIAS
|
||||
int progcomp_alias = 0; /* unavailable to user code for now */
|
||||
#endif
|
||||
|
||||
/* These are used to manage the arrays of strings for possible completions. */
|
||||
ITEMLIST it_aliases = { 0, it_init_aliases, (STRINGLIST *)0 };
|
||||
ITEMLIST it_arrayvars = { LIST_DYNAMIC, it_init_arrayvars, (STRINGLIST *)0 };
|
||||
@@ -183,6 +185,9 @@ COMPSPEC *pcomp_curcs;
|
||||
const char *pcomp_curcmd;
|
||||
const char *pcomp_curtxt;
|
||||
|
||||
char *pcomp_line;
|
||||
int pcomp_ind;
|
||||
|
||||
#ifdef DEBUG
|
||||
/* Debugging code */
|
||||
static void
|
||||
@@ -1380,14 +1385,14 @@ gen_compspec_completions (cs, cmd, word, start, end, foundp)
|
||||
/* If we have a command or function to execute, we need to first break
|
||||
the command line into individual words, find the number of words,
|
||||
and find the word in the list containing the word to be completed. */
|
||||
line = substring (rl_line_buffer, start, end);
|
||||
line = substring (pcomp_line, start, end);
|
||||
llen = end - start;
|
||||
|
||||
#ifdef DEBUG
|
||||
debug_printf ("command_line_to_word_list (%s, %d, %d, %p, %p)",
|
||||
line, llen, rl_point - start, &nw, &cw);
|
||||
line, llen, pcomp_ind - start, &nw, &cw);
|
||||
#endif
|
||||
lwords = command_line_to_word_list (line, llen, rl_point - start, &nw, &cw);
|
||||
lwords = command_line_to_word_list (line, llen, pcomp_ind - start, &nw, &cw);
|
||||
/* If we skipped a NULL word at the beginning of the line, add it back */
|
||||
if (lwords && lwords->word && cmd[0] == 0 && lwords->word->word[0] != 0)
|
||||
{
|
||||
@@ -1414,7 +1419,7 @@ gen_compspec_completions (cs, cmd, word, start, end, foundp)
|
||||
if (cs->funcname)
|
||||
{
|
||||
foundf = 0;
|
||||
tmatches = gen_shell_function_matches (cs, cmd, word, line, rl_point - start, lwords, nw, cw, &foundf);
|
||||
tmatches = gen_shell_function_matches (cs, cmd, word, line, pcomp_ind - start, lwords, nw, cw, &foundf);
|
||||
if (foundf != 0)
|
||||
found = foundf;
|
||||
if (tmatches)
|
||||
@@ -1434,7 +1439,7 @@ gen_compspec_completions (cs, cmd, word, start, end, foundp)
|
||||
|
||||
if (cs->command)
|
||||
{
|
||||
tmatches = gen_command_matches (cs, cmd, word, line, rl_point - start, lwords, nw, cw);
|
||||
tmatches = gen_command_matches (cs, cmd, word, line, pcomp_ind - start, lwords, nw, cw);
|
||||
if (tmatches)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
@@ -1608,7 +1613,8 @@ gen_progcomp_completions (ocmd, cmd, word, start, end, foundp, retryp, lastcs)
|
||||
|
||||
/* The driver function for the programmable completion code. Returns a list
|
||||
of matches for WORD, which is an argument to command CMD. START and END
|
||||
bound the command currently being completed in rl_line_buffer. */
|
||||
bound the command currently being completed in pcomp_line (usually
|
||||
rl_line_buffer). */
|
||||
char **
|
||||
programmable_completions (cmd, word, start, end, foundp)
|
||||
const char *cmd;
|
||||
@@ -1619,26 +1625,95 @@ programmable_completions (cmd, word, start, end, foundp)
|
||||
STRINGLIST *ret;
|
||||
char **rmatches, *t;
|
||||
int found, retry, count;
|
||||
char *ocmd;
|
||||
int oend;
|
||||
#if defined (ALIAS)
|
||||
alias_t *al;
|
||||
#endif
|
||||
|
||||
lastcs = 0;
|
||||
found = count = 0;
|
||||
|
||||
pcomp_line = rl_line_buffer;
|
||||
pcomp_ind = rl_point;
|
||||
|
||||
ocmd = (char *)cmd;
|
||||
oend = end;
|
||||
|
||||
do
|
||||
{
|
||||
retry = 0;
|
||||
|
||||
/* We look at the basename of CMD if the full command does not have
|
||||
an associated COMPSPEC. */
|
||||
ret = gen_progcomp_completions (cmd, cmd, word, start, end, &found, &retry, &lastcs);
|
||||
ret = gen_progcomp_completions (ocmd, ocmd, word, start, oend, &found, &retry, &lastcs);
|
||||
if (found == 0)
|
||||
{
|
||||
t = strrchr (cmd, '/');
|
||||
t = strrchr (ocmd, '/');
|
||||
if (t && *(++t))
|
||||
ret = gen_progcomp_completions (t, cmd, word, start, end, &found, &retry, &lastcs);
|
||||
ret = gen_progcomp_completions (t, ocmd, word, start, oend, &found, &retry, &lastcs);
|
||||
}
|
||||
|
||||
if (found == 0)
|
||||
ret = gen_progcomp_completions (DEFAULTCMD, cmd, word, start, end, &found, &retry, &lastcs);
|
||||
ret = gen_progcomp_completions (DEFAULTCMD, ocmd, word, start, oend, &found, &retry, &lastcs);
|
||||
|
||||
#if defined (ALIAS)
|
||||
/* Look up any alias for CMD, try to gen completions for it */
|
||||
/* Look up the alias, find the value, build a new line replacing CMD
|
||||
with that value, offsetting PCOMP_IND and END appropriately, reset
|
||||
PCOMP_LINE to the new line and OCMD with the new command name, then
|
||||
call gen_progcomp_completions again. We could use alias_expand for
|
||||
this, but it does more (and less) than we need right now. */
|
||||
if (found == 0 && retry == 0 && progcomp_alias && (al = find_alias (ocmd)))
|
||||
{
|
||||
char *ncmd, *nline, *ntxt;
|
||||
int ind, lendiff;
|
||||
size_t nlen, olen, llen;
|
||||
|
||||
/* We found an alias for OCMD. Take the value and build a new line */
|
||||
ntxt = al->value;
|
||||
nlen = strlen (ntxt);
|
||||
if (nlen == 0)
|
||||
break;
|
||||
olen = strlen (ocmd);
|
||||
lendiff = nlen - olen; /* can be negative */
|
||||
llen = strlen (pcomp_line);
|
||||
|
||||
nline = (char *)xmalloc (llen + lendiff + 1);
|
||||
if (start > 0)
|
||||
strncpy (nline, pcomp_line, start);
|
||||
strncpy (nline + start, ntxt, nlen);
|
||||
strcpy (nline + start + nlen, pcomp_line + start + olen);
|
||||
|
||||
/* Find the first word of the alias value and use that as OCMD. We
|
||||
don't check the alias value to see whether it begins with a valid
|
||||
command name, so this can be fooled. */
|
||||
ind = skip_to_delim (ntxt, 0, "()<>;&| \t\n", SD_NOJMP|SD_COMPLETE); /*)*/
|
||||
if (ind > 0)
|
||||
ncmd = substring (ntxt, 0, ind);
|
||||
else
|
||||
{
|
||||
free (nline);
|
||||
break; /* will free pcomp_line and ocmd later */
|
||||
}
|
||||
|
||||
/* Adjust PCOMP_IND and OEND appropriately */
|
||||
pcomp_ind += lendiff;
|
||||
oend += lendiff;
|
||||
|
||||
/* Set up values with new line. WORD stays the same. */
|
||||
if (ocmd != cmd)
|
||||
free (ocmd);
|
||||
if (pcomp_line != rl_line_buffer)
|
||||
free (pcomp_line);
|
||||
|
||||
ocmd = ncmd;
|
||||
pcomp_line = nline;
|
||||
|
||||
/* And go back and start over. */
|
||||
retry = 1;
|
||||
}
|
||||
#endif /* ALIAS */
|
||||
|
||||
count++;
|
||||
|
||||
@@ -1650,6 +1725,11 @@ programmable_completions (cmd, word, start, end, foundp)
|
||||
}
|
||||
while (retry);
|
||||
|
||||
if (pcomp_line != rl_line_buffer)
|
||||
free (pcomp_line);
|
||||
if (ocmd != cmd)
|
||||
free (ocmd);
|
||||
|
||||
if (ret)
|
||||
{
|
||||
rmatches = ret->list;
|
||||
@@ -1664,6 +1744,10 @@ programmable_completions (cmd, word, start, end, foundp)
|
||||
if (lastcs) /* XXX - should be while? */
|
||||
compspec_dispose (lastcs);
|
||||
|
||||
/* XXX restore pcomp_line and pcomp_ind? */
|
||||
pcomp_line = rl_line_buffer;
|
||||
pcomp_ind = rl_point;
|
||||
|
||||
return (rmatches);
|
||||
}
|
||||
|
||||
|
||||
+11
@@ -77,6 +77,12 @@ typedef struct compspec {
|
||||
#define COPT_PLUSDIRS (1<<7)
|
||||
#define COPT_NOSORT (1<<8)
|
||||
|
||||
#define COPT_LASTUSER COPT_NOSORT
|
||||
|
||||
#define PCOMP_RETRYFAIL (COPT_LASTUSER << 1)
|
||||
#define PCOMP_NOTFOUND (COPT_LASTUSER << 2)
|
||||
|
||||
|
||||
/* List of items is used by the code that implements the programmable
|
||||
completions. */
|
||||
typedef struct _list_of_items {
|
||||
@@ -103,7 +109,12 @@ typedef struct _list_of_items {
|
||||
#define DEFAULTCMD "_DefaultCmD_"
|
||||
|
||||
extern HASH_TABLE *prog_completes;
|
||||
|
||||
extern char *pcomp_line;
|
||||
extern int pcomp_ind;
|
||||
|
||||
extern int prog_completion_enabled;
|
||||
extern int progcomp_alias;
|
||||
|
||||
/* Not all of these are used yet. */
|
||||
extern ITEMLIST it_aliases;
|
||||
|
||||
@@ -18,3 +18,15 @@ one
|
||||
two
|
||||
three
|
||||
four
|
||||
Error: bar
|
||||
ok 1
|
||||
ok 2
|
||||
text
|
||||
whoops: nullalias
|
||||
foo
|
||||
a
|
||||
a b
|
||||
a b
|
||||
a a b
|
||||
ok 3
|
||||
ok 4
|
||||
|
||||
@@ -39,3 +39,4 @@ unalias foo bar baz
|
||||
${THIS_SH} ./alias1.sub
|
||||
${THIS_SH} ./alias2.sub
|
||||
${THIS_SH} ./alias3.sub
|
||||
${THIS_SH} ./alias4.sub
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
shopt -s expand_aliases
|
||||
|
||||
# from an austin-group report
|
||||
alias foo="echo 'Error:"
|
||||
foo bar'
|
||||
|
||||
# from some FreeBSD sh tests
|
||||
|
||||
v=1
|
||||
alias a='unalias -a
|
||||
v=2'
|
||||
eval a
|
||||
[ "$v" = 2 ] && echo ok 1
|
||||
v=1
|
||||
alias a='unalias a
|
||||
v=2'
|
||||
eval a
|
||||
[ "$v" = 2 ] && echo ok 2
|
||||
|
||||
# make sure command doesn't ever reset anything even if it's made a keyword
|
||||
unalias -a
|
||||
alias command=command
|
||||
alias true='echo bad'
|
||||
eval 'command true'
|
||||
|
||||
unalias -a
|
||||
alias alias0=command
|
||||
alias true='echo bad'
|
||||
eval 'alias0 true'
|
||||
|
||||
# make sure null aliases are ok
|
||||
unalias -a
|
||||
alias nullalias=''
|
||||
alias foo='echo '
|
||||
foo nullalias text
|
||||
unalias foo
|
||||
|
||||
# aliases shouldn't be expanded in quoted strings even when the previous word
|
||||
# is an alias whose expansion ends in a space
|
||||
alias foo="echo 'whoops: "
|
||||
foo nullalias'
|
||||
|
||||
unalias -a
|
||||
|
||||
# recursive alias definitions
|
||||
alias echo=echo
|
||||
eval echo foo
|
||||
|
||||
alias echo='echo a'
|
||||
|
||||
echo
|
||||
echo b
|
||||
eval echo b
|
||||
echo $(eval echo b)
|
||||
|
||||
unalias -a
|
||||
|
||||
# alias expansion when in a command position after redirections
|
||||
alias e=echo
|
||||
eval '</dev/null e ok 3'
|
||||
eval 'a=true e ok 4'
|
||||
Reference in New Issue
Block a user