rcaloras / bash-preexec

⚡ preexec and precmd functions for Bash just like Zsh.
MIT License
862 stars 94 forks source link

preexec $1 is missing some commands #147

Open alperyilmaz opened 11 months ago

alperyilmaz commented 11 months ago

I'm recording command history in certain format into daily log files. I was using PROMPT_COMMAND to save the last command to a file. I was using echo "$(history -p \!-1)" to save the last item from history to a file. But that is causing some problems: 1) the command is recorded in log file when next command is run. 2) due to ignored commands (ls, cd, ll, clear, etc.) "last command" approach becomes out of sync.

I discovered bash-preexec and it is exactly what I want "record the command as soon as I hit Enter with preexec() function"

I updated by .bashrc accordingly, the concept is working but somehow preexec is missing some commands and do not record them and instead prints the previous command to log file. The ones that I noticed are;

Here's my old PROMPT_COMMAND:

export PROMPT_COMMAND='history -a; history -n; if [ "$(id -u)" -ne 0 ]; then echo -ne "$(date "+%Y-%m-%d.%H:%M:%S")\t$(hostname)\t$(pwd)\t"; echo "$(history -p \!-1)" >> ~/.logs/bash-history-$(hostname)-$(date "+%Y-%m-%d").log; fi'

Here's my new PROMPT_COMMAND:

export PROMPT_COMMAND='history -a; history -n;'

And here's my preexec() function:

preexec() { echo -e "$(date "+%Y-%m-%d.%H:%M:%S")\t$(hostname)\t$(pwd)\t$1" >> ~/.logs/bash-history-$(hostname)-$(date "+%Y-%m-%d").log; }

What should I do so that whatever I write in prompt is saved to log file as soon as I hit Enter

akinomyoga commented 11 months ago

The ones that I noticed are;

  • ignored commands, ls, ll, clear

I guess that it is caused by your HISTIGNORE. If the command matches any of the patterns in HISTIGNORE, it is not registered into the command history of Bash, so history -p '!-1' will pick up the last command that does not match HISTIGNORE even though preexec is invoked on the commands matching HISTIGNORE.

But this problem should also happen with your previous approach using PROMPT_COMMAND as it also uses history -p '!-1'.

You can also refer to https://github.com/rcaloras/bash-preexec/issues/6#issuecomment-113971824 for the settings that can affect the behavior of history -p '!-1'.

  • function definitions are not recorded in the log file (for example :hello-world () { echo "hello world!"; })

This is already reported in #6. This is a limitation of the current way of implementing preexec. The current implementation relies on the DEBUG trap, but DEBUG trap is not activated for function definitions.

What should I do so that whatever I write in prompt is saved to log file as soon as I hit Enter

If you can assume Bash >= 4.4, you may use PS0='$(your command)'. Since your commands do not modify the shell environment, you can use the command substitution $() which will be run in a subshell. Note that the general preexec cannot be implemented using PS0='$(your command)' since preexec also assumes modifications to the environment of the main shell by the registered command. See also discussions in #28.