Open andychu opened 5 years ago
Good resources, I will look at FZF. I had not heard of it.
OK thanks!
The thread helped clarify what I'd want in Oil for history:
https://news.ycombinator.com/item?id=20057323
Basically it should be a structured text file. Coincidentally I wrote this the other day because @drwilly is working on xargs, which also needs structured data:
https://github.com/oilshell/oil/wiki/Structured-Data-in-Oil
The point is that you probably want history in SQL for two reasons:
HISTCONTROL=erasedups
is implemented).I think what'ss weird about bash history is this:
That's why it's so weird between "sessions"! At least I think so.
This thread also points to the benefit of having a real programming language in shell. Instead of a PROMPT_COMMAND
string to evaluate, we could have a hook:
func whenCommandFinished(command_string, evaluated_argv, timestamp, status, elapsed_time, ...) {
# do something yourself with history, like put it in a sqlite database, or upload it to your own server, etc.
}
Pretty much agree.
The other thing I would add is making history more robust in the presence of events which kill the shell before it has a chance to save its history.
Either a function hook or a trap.
At least one comment hints at how controversial this sort of thing will be :P
On Fri, May 31, 2019, 10:03 andychu notifications@github.com wrote:
OK thanks!
The thread helped clarify what I'd want in Oil for history:
https://news.ycombinator.com/item?id=20057323
And coincidentally I wrote this the other day because @drwilly https://github.com/drwilly is working on xargs, which also needs structured data:
https://github.com/oilshell/oil/wiki/Structured-Data-in-Oil
Anyway, the point is that you probably want history in SQL for two reasons:
- because you want fields without parsing them (usually done incorrectly). That can be done with the simple TSV2 proposal. Oil will parse that so you don't have to, but you can also grep the file if you want.
- for concurrency. I don't think this is a problem for append only files (although admittedly I wonder how HISTCONTROL=erasedups is implemented).
I think what is weird about bash is this:
- history is kept in a buffer in memory
- on shell's exit, the whole thing is appended to a file.
That's why it's so weird between sessions! At least I think so.
This thread also points to the benefit of having a real programming language in shell. Instead of a PROMPT_COMMAND string to evaluate, we could have a hook:
func whenCommandFinished(command_string, evaluated_argv, timestamp, status, elapsed_time, ...) {
do something yourself with history, like put it in a sqlite database, or upload it to your own server, etc.
}
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/oilshell/oil/issues/320?email_source=notifications&email_token=AAAC3W47UY3GL4SQM7P7LILPYFK4XA5CNFSM4HRPAND2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODWVZZLA#issuecomment-497786028, or mute the thread https://github.com/notifications/unsubscribe-auth/AAAC3WYTRSOL56T32ZVLJTLPYFK4XANCNFSM4HRPANDQ .
I'm designing a history extension/replacement for bash and zsh and instead of having awkward two-level history I have a daemon-client type situation. Maybe oilshell could do something similar.
@curusarn I'd be interested in seeing what you've done for bash and zsh!
It would be interesting for Oil to support some kind of external protocol so people can plug in their own logic.
Although one limitation is that we use readline
for history, which has its own file format. But bash has that issue too, so I'm curious how you solved it.
@andychu Sorry for the long silence.
Readline is pretty difficult to work with.
The idea behind my project is to provide context-based history enhancement for zsh and bash. So I have a daemon that records the history with metadata and then handles all the interaction with history.
There are multiple ways I need to integrate with the shell:
To collect the history I run custom functions before/after each command using bash-preexec. It uses $PROMPT_COMMAND
and DEBUG trap. It works with some minor issues.
Executing custom commands through readline bindings is problematic. There is bind -x
builtin in bash to bind commands to key sequences but readline redraws the whole prompt when the command executes which is pretty slow. I asked in a readline mailing list about it but they told me it's not an easy thing to change at all (unsurprisingly). The redraw itself is so slow I have disabled arrow key bindings in bash in my project for now.
I didn't implement the binding for Ctrl+R yet but I want it to open an app similar to hstr except my app will use all the extra data for searching. There should be no problem to do this since hstr
already works in bash.
All of the above is much easier to do in zsh then in bash.
Integrating with bash and readline is always a painful experience riddled with weird behavior and missing features. Integrating with zsh and ZLE (zsh line editor) is fairly straight forward.
Link to my project for more context and more info.
I'm not sure exactly how much of the difficulties I encountered were caused by readline itself and how much I can blame bash. My intuition is that the biggest problem are the bindings because anything else than native readline history functions takes the performance hit when redrawing.
I've also been picking at a bash-specific history module (opinionated; uses sqlite, also stays compatible with the underlying history functionality). I'm not promoting it for others to use, yet, but it's been in my shell for close to a year now, I guess. Don't have time for a longer comment atm, but I'll get notifications, and you'll know I have opinions. :)
@abathur What interface are you using to glue bash together with sqlite? Is it $PROMPT_COMMAND
?
That seems like a fragile interface but I suppose it's already there and a lot of people are using it.
I'm more interested in providing a good interface for Oil than developing this myself. Though it already implements $PROMPT_COMMAND
... maybe that's good enough but I'd be surprised if we couldn't do better.
Yep.
Indirectly, though--I've abstracted most messy implementation parts into a shell library (to keep them away from the history module itself, minimize duplicated work in other parts of my profile, and make it possible to share the PROMPT_COMMAND).
I do think Oil can do better, though I'm not sure it's incompatible with supporting PROMPT_COMMAND. Can probably discuss on zulip sometime soon.
Oil could support preexec
and precmd
hooks that are supported by zsh. These could be easily used to plug in arbitrary history extensions to oil shell.
precmd Executed before each prompt. Note that precommand functions are not re-executed simply because the command line is redrawn, as happens, for example, when a notification about an exiting job is displayed.
preexec Executed just after a command has been read and is about to be executed. If the history mechanism is active (regardless of whether the line was discarded from the history buffer), the string that the user typed is passed as the first argument, otherwise it is an empty string. The actual command that will be executed (including expanded aliases) is passed in two different forms: the second argument is a single-line, size-limited version of the command (with things like function bodies elided); the third argument contains the full text that is being executed.
Yeah I think those hooks are a good idea, and the different versions of the command are what I wanted to sort out:
echo $FOO
['echo', 'foovalue']
. I would want to keep this as an argv array, not "text" as my reading of the zsh manual excerpt implies.pre- and post- alias expansion is another possibility, and probably not hard, although I'm not sure how useful it is. (Almost all aliases can simply be shell functions.)
This distinction appears to be missing from bash's history mechanism on the "output side".
I would also favor something like prompt_hook() { }
over $PROMPT_COMMAND
.
Just like bash has command_not_found() { }
now.
This also relates to $PS1
and $PS4
. Basically the string hooks are annoying and error prone IMO.
related:
$PS1
is #498 $PS4
is #583 https://news.ycombinator.com/item?id=25946055
Good comment here
My histories are always saved because each shell instance gets its own HISTFILE, like so:
export HISTFILE=$HOME/.history/${TTY##\*/}.$SHLVL
As I use different terminal windows for different tasks, this keeps history files rather concise thematically.
And I let the shell add timestamps too, so I can grep for entries produced during a certain time span:
zsh:
setopt EXTENDEDHISTORY # add timestamps
bash:
HISTTIMEFORMAT="%F %T "
This is a summary of Better Bash History discussion on HN
@emdash There is lots of interesting feedback here about history, including someone putting their history in an sqlite DB! Bash is crufty yet it's pretty amazing what people manage to hack on to it!
Some takeaways:
$PROMPT_COMMAND
because lot of people are using it!Things people are doing:
cd
'd into. Thus, all of thecd
commands that get written to my history use absolute paths and are re-usable no matter where I amcd
.*argv
array as well as the raw text?History:
Other interesting quotes, not about history: