On 01/01/2019 14:27, Martijn Dekker wrote:
On dash and on gwsh, the 'fc -s' command, that re-executes a command
from the history, executes the command repeatedly in an infinite loop.
It should execute it just once.
This is caused by the block with the XXX comment in src/histedit.c:
if (displayhist && hist) {
/*
* XXX what about recursive and
* relative histnums.
*/
history(hist, &he, H_ENTER, s);
}
This changes the position in the history list and also clobbers he, so
the if (he.num == last) check afterwards always returns false, and if
the check was supposed to return false, the next history(hist, &he,
direction) would not do what was intended.
The immediate problem can be fixed either by dropping support for the
non-standard and undocumented fc -s first last and immediately breaking
out of the loop, or by restoring the position (restoring he at the same
time).
But there are more problems: H_ENTER adds a new command to the history.
bash and ksh do not do this:
echo hello
fc -s 1
fc -l
will show (bash, but ksh is similar)
hello
1 echo hello
2 echo hello
That is, the echo hello command appears twice in the history, but the fc
-s 1 command does not appear at all. This is what POSIX probably[*]
requires as well.
By the time fc is called, the fc line is already in the history, so to
get the bash/ksh behaviour, the current command would need to be
overwritten. The documentation of libedit does not show any option which
can overwrite entries already created. It documents H_ADD and H_APPEND,
which can append, and has an undocumented H_REPLACE used by the equally
undocumented replace_history_entry() function in <editline/readline.h>.
I do not know yet if it makes sense to start using this.
Also, when neither -s nor -l is specified and an editor is invoked, the
new command is supposed to be entered into the history as well. That too
is not implemented.
Cheers,
Harald van Dijk
[*] POSIX specifies "When commands are edited (when the -l option is not
specified), [...]", but in the case of fc -s 1, commands are not edited
and the -l option is also not specified. It makes most sense to say that
what follows also applies to fc -s.