fix for $_ when executing $PROMPT_COMMAND; fix for extra line in history after here-document in command substitution

This commit is contained in:
Chet Ramey
2023-02-13 10:48:05 -05:00
parent 3eab48247a
commit d7a6d947df
11 changed files with 140 additions and 72 deletions
+31 -6
View File
@@ -5272,8 +5272,9 @@ arrayfunc.c
---
parse.y
- discard_until: now returns the last character read. If we get an
EOF while processing a comment, return EOF
- shell_getc: if discard_until returns EOF, return yacc_EOF
EOF while processing a comment, return EOF (rarely happens;
shell_getc returns EOF only under certain circumstances)
- read_token: if discard_until returns EOF, return yacc_EOF
input.h
- bclearerror: new macro, clears the B_ERROR flag in the buffered
@@ -5294,7 +5295,31 @@ doc/{bash.1,bashref.texi}
2/8
---
bashline.c
- alias_expand_line: if alias_expand doesn't change rl_line_buffer,
just return right away without changing rl_point. Inspired by a
report from Addison Brendtro <addison.brendtro@gmail.com>
- history_expand_line: ditto
- set_up_new__line: if the new line doesn't change rl_line_buffer,
just return right away without changing rl_point. Affects
alias-expand-line, history-expand-line, and history-and-alias-expand-line.
Inspired by a report from
Addison Brendtro <addison.brendtro@gmail.com>
builtins/declare.def
- declare_internal: make multiple calls to `local -' at the same
context have no effect after the first one. That way we don't keep
overwriting the saved option set. Report and fix from
Emanuele Torre <torreemanuele6@gmail.com>
2/10
----
execute_cmd.[ch]
- bind_lastarg: now a public function
parse.y
- execute_variable_command: call bind_lastarg instead of bind_variable
to avoid exporting $_ if allexport is set. Fix from
Emanuele Torre <torreemanuele6@gmail.com>
bashhist.c
- history_delimiting_chars: if we're parsing some kind of delimited
construct that's *not* a quoted string, don't bother adding an extra
newline to the history if the current history entry already ends in
a newline. From https://savannah.gnu.org/support/?110838 via
Ganapathi Kamath <hgkamath@hotmail.com>
+7 -14
View File
@@ -2713,6 +2713,13 @@ set_up_new_line (char *new_line)
{
int old_point, at_end;
/* If we didn't expand anything, don't change anything. */
if (STREQ (new_line, rl_line_buffer))
{
free (new_line);
return;
}
old_point = rl_point;
at_end = rl_point == rl_end;
@@ -2741,13 +2748,6 @@ alias_expand_line (int count, int ignore)
new_line = alias_expand (rl_line_buffer);
/* If we didn't expand anything, don't change anything. */
if (new_line && STREQ (new_line, rl_line_buffer))
{
free (new_line);
return (0);
}
if (new_line)
{
set_up_new_line (new_line);
@@ -2770,13 +2770,6 @@ history_expand_line (int count, int ignore)
new_line = history_expand_line_internal (rl_line_buffer);
/* If we didn't expand anything, don't change anything. */
if (new_line && STREQ (new_line, rl_line_buffer))
{
free (new_line);
return (0);
}
if (new_line)
{
set_up_new_line (new_line);
+12 -4
View File
@@ -409,11 +409,19 @@ declare_internal (WORD_LIST *list, int local_var)
if (local_var && variable_context && STREQ (name, "-"))
{
int o;
o = localvar_inherit;
localvar_inherit = 0;
var = make_local_variable ("-", 0);
FREE (value_cell (var)); /* just in case */
value = get_current_options ();
var_setvalue (var, value);
VSETATTR (var, att_invisible);
localvar_inherit = o;
if (value_cell (var) == NULL) /* no duplicate instances */
{
value = get_current_options ();
var_setvalue (var, value);
VSETATTR (var, att_invisible);
}
NEXT_VARIABLE ();
}
+3 -1
View File
@@ -9278,7 +9278,9 @@ is used within a function, it causes the variable
to have a visible scope restricted to that function and its children.
If \fIname\fP is \-, the set of shell options is made local to the function
in which \fBlocal\fP is invoked: shell options changed using the
\fBset\fP builtin inside the function are restored to their original values
\fBset\fP builtin inside the function
after the call to \fBlocal\fP
are restored to their original values
when the function returns.
The restore is effected as if a series of \fBset\fP commands were executed
to restore the values that were in place before the function.
+3 -1
View File
@@ -4787,7 +4787,9 @@ The @var{option} can be any of the options accepted by @code{declare}.
children.
If @var{name} is @samp{-}, the set of shell options is made local to the
function in which @code{local} is invoked: shell options changed using
the @code{set} builtin inside the function are restored to their original
the @code{set} builtin inside the function
after the call to @code{local}
are restored to their original
values when the function returns.
The restore is effected as if a series of @code{set} commands were executed
to restore the values that were in place before the function.
+50 -32
View File
@@ -3,7 +3,7 @@
/* See Makefile for compilation details. */
/*
Copyright (C) 1999-2009,2022 Free Software Foundation, Inc.
Copyright (C) 1999-2009,2022-2023 Free Software Foundation, Inc.
This file is part of GNU Bash.
Bash is free software: you can redistribute it and/or modify
@@ -135,10 +135,12 @@ mkdir_builtin (WORD_LIST *list)
static int
make_path (char *path, int user_mode, int nmode, int parent_mode)
{
int oumask;
mode_t oumask;
struct stat sb;
char *p, *npath;
int tail;
/* If we don't have to do any work, don't do any work. */
if (stat (path, &sb) == 0)
{
if (S_ISDIR (sb.st_mode) == 0)
@@ -166,48 +168,64 @@ make_path (char *path, int user_mode, int nmode, int parent_mode)
while (*p == '/')
p++;
while (p = strchr (p, '/'))
tail = 0;
while (tail == 0)
{
*p = '\0';
if (stat (npath, &sb) != 0)
if (*p == '\0')
tail = 1;
else
p = strchr (p, '/');
if (p)
*p = '\0';
else
tail = 1;
if (mkdir (npath, 0) < 0)
{
if (mkdir (npath, 0))
/* "Each dir operand that names an existing directory shall be
ignored without error." */
if (errno == EEXIST || errno == EISDIR)
{
int e = errno;
int fail = 0;
if (stat (npath, &sb) != 0)
{
fail = 1;
builtin_error ("cannot create directory `%s': %s", npath, strerror (e));
}
else if (e == EEXIST && S_ISDIR (sb.st_mode) == 0)
{
fail = 1;
builtin_error ("`%s': file exists but is not a directory", npath);
}
if (fail)
{
umask (original_umask);
free (npath);
return 1;
}
}
else
{
builtin_error ("cannot create directory `%s': %s", npath, strerror (errno));
umask (original_umask);
free (npath);
return 1;
}
if (chmod (npath, parent_mode) != 0)
{
builtin_error ("cannot chmod directory `%s': %s", npath, strerror (errno));
umask (original_umask);
free (npath);
return 1;
}
}
else if (S_ISDIR (sb.st_mode) == 0)
{
builtin_error ("`%s': file exists but is not a directory", npath);
umask (original_umask);
free (npath);
return 1;
}
*p++ = '/'; /* restore slash */
while (*p == '/')
if (chmod (npath, (tail == 0) ? parent_mode : nmode) != 0)
{
builtin_error ("cannot chmod directory `%s': %s", npath, strerror (errno));
umask (original_umask);
free (npath);
return 1;
}
if (tail == 0)
*p++ = '/'; /* restore slash */
while (p && *p == '/') /* skip consecutive slashes or trailing slash */
p++;
}
/* Create the final directory component. */
if (stat (npath, &sb) && mkdir (npath, nmode))
{
builtin_error ("cannot create directory `%s': %s", npath, strerror (errno));
umask (original_umask);
free (npath);
return 1;
}
umask (original_umask);
free (npath);
return 0;
+1 -2
View File
@@ -121,7 +121,6 @@ extern int close (int);
/* Static functions defined and used in this file. */
static void close_pipes (int, int);
static void do_piping (int, int);
static void bind_lastarg (char *);
static int shell_control_structure (enum command_type);
static void cleanup_redirects (REDIRECT *);
@@ -4000,7 +3999,7 @@ execute_cond_command (COND_COM *cond_command)
}
#endif /* COND_COMMAND */
static void
void
bind_lastarg (char *arg)
{
SHELL_VAR *var;
+1
View File
@@ -120,4 +120,5 @@ extern void close_all_files (void);
extern void restore_funcarray_state (struct func_array_state *);
#endif
extern void bind_lastarg (char *);
#endif /* _EXECUTE_CMD_H_ */
+22 -2
View File
@@ -2849,7 +2849,7 @@ execute_variable_command (const char *command, const char *vname)
parse_and_execute (savestring (command), vname, SEVAL_NONINT|SEVAL_NOHIST|SEVAL_NOOPTIMIZE);
restore_parser_state (&ps);
bind_variable ("_", last_lastarg, 0);
bind_lastarg (last_lastarg);
FREE (last_lastarg);
if (token_to_read == '\n') /* reset_parser was called */
@@ -5636,7 +5636,27 @@ history_delimiting_chars (const char *line)
last_was_heredoc = 0;
if (dstack.delimiter_depth != 0)
return ("\n");
{
char ch;
HIST_ENTRY *current;
size_t curlen;
ch = current_delimiter(dstack);
if (shellquote(ch))
return ("\n");
else if (ch == '(') /* ) and maybe for other non-quote-char delimiters */
{
using_history ();
current = previous_history ();
curlen = current ? strlen (current->line) : 0;
/* If we're not reading some kind of quoted string, don't bother
adding a newline if the current history entry already ends in a
newline. It's just extra. */
return ((curlen > 0 && current->line[curlen - 1] == '\n') ? "" : "\n");
}
else
return ("\n");
}
/* We look for current_command_line_count == 2 because we are looking to
add the first line of the body of the here document (the second line
BIN
View File
Binary file not shown.
+10 -10
View File
@@ -11,7 +11,7 @@ msgstr ""
"Project-Id-Version: bash 5.2-rc1\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-01-11 14:50-0500\n"
"PO-Revision-Date: 2022-07-28 01:08+0800\n"
"PO-Revision-Date: 2023-02-09 00:40+0800\n"
"Last-Translator: Yi-Jyun Pan <pan93412@gmail.com>\n"
"Language-Team: Chinese (traditional) <zh-l10n@lists.linux.org.tw>\n"
"Language: zh_TW\n"
@@ -20,7 +20,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Bugs: Report translation errors to the Language-Team address.\n"
"X-Generator: Poedit 3.1.1\n"
"X-Generator: Poedit 3.2.2\n"
#: arrayfunc.c:66
msgid "bad array subscript"
@@ -2762,7 +2762,7 @@ msgstr ""
" 變更目前目錄至 <目錄>。預設的 <目錄> 是 shell 變數 HOME\n"
" 的值。\n"
" \n"
" 變數 CDPATH 定義了含有 <目錄> 的目錄搜尋路徑,其中不同的目錄名稱由冒號 (:)分隔。\n"
" 變數 CDPATH 定義了含有 <目錄> 的目錄搜尋路徑,其中不同的目錄名稱由冒號 (:) 分隔。\n"
" 一個空的目錄名稱表示目前目錄。如果要切換到的 <目錄> 由斜線 (/) 開頭,則 CDPATH\n"
" 變數不會被使用。\n"
" \n"
@@ -3188,7 +3188,7 @@ msgstr ""
" Getopts 被 shell 過程用來將可定位的參數解析為選項。\n"
" \n"
" <選項字串> 字串包含待識別的選項字母。如果一個字母後面跟\n"
" 著號,則該選項需要一個參數,這個參數應利用空格與選項分開。\n"
" 著號,則該選項需要一個參數,這個參數應利用空格與選項分開。\n"
" \n"
" 每次呼叫時,getopts 會將下一個選項放到 shell 變數 $name\n"
" 中,如果 name 變數不存在則先將其初始化,而下一個待處\n"
@@ -5007,22 +5007,22 @@ msgstr ""
"常用 shell 變數名稱和使用。\n"
" \n"
" BASH_VERSION\t目前 Bash 的版本資訊。\n"
" CDPATH\t用於「cd」指令參數搜尋分號分隔的目錄列表\n"
" CDPATH\t傳入「cd」作為引數,冒號分隔的欲搜尋目錄清單\n"
" GLOBIGNORE\t路徑擴充套件時忽略的檔名符合模式列表,\n"
" \t\t以號分隔。\n"
" HISTFILE\t您的令歷史記錄存放的檔案名稱。\n"
" \t\t以號分隔。\n"
" HISTFILE\t您的令歷史記錄存放的檔案名稱。\n"
" HISTFILESIZE\t歷史記錄檔案最多可以儲存的列數。\n"
" HISTSIZE\t一個執行的 shell 最多可以訪問的歷史記錄令列數。\n"
" HISTSIZE\t一個執行的 shell 最多可以存取的歷史記錄令列數。\n"
" HOME\t您登入目錄的完整路徑。\n"
" HOSTNAME\t目前主機的主機名稱。\n"
" HOSTTYPE\t目前版本的 BASH 在其之上執行的 CPU 類型。\n"
" IGNOREEOF\t控制 shell 收到檔案結束符做為單一輸入後的\n"
" \t\t動作。如果設定這個變數,則它的值是 shell 結束之前在\n"
" \t\t一個空列上可以連續看到的檔案結束符數量(預設為 10)。\n"
" \t\t未設定時,檔案結束符標著輸入的結束。\n"
" \t\t未設定時,檔案結束符標著輸入的結束。\n"
" MACHTYPE\t描述目前執行 Bash 的系統字串。\n"
" MAILCHECK\tBash 檢測新郵件的頻率,以秒為單位。\n"
" MAILPATH\tBash 從中檢測新郵件的檔案列表,以號分隔。\n"
" MAILPATH\tBash 從中檢測新郵件的檔案列表,以號分隔。\n"
" OSTYPE\t執行 Bash 的 Unix 版本。\n"
" PATH\t當尋找指令時搜尋的目錄列表,以冒號分隔。\n"
" PROMPT_COMMAND\t印出每一個主提示符之前執行的命\n"