rcaloras / bash-preexec Goto Github PK
View Code? Open in Web Editor NEW⚡ preexec and precmd functions for Bash just like Zsh.
License: MIT License
⚡ preexec and precmd functions for Bash just like Zsh.
License: MIT License
This is more of a support question. I'm wondering if this is a valid use case:
precmd() {
cmdpath=`which $1`
if [[ "$cmdpath" =~ "^(/usr)?/sbin/.*" ]]; then
sudo $1
fi
}
If I'm running anything in /sbin (requiring root) then I'd like to prepend sudo to the command automatically.
I Think it will be a nice feature to have a method of supporting logs of mysql queries fired from a mysql shell.
When decelerating detecting semicolon as the first character and overnight default error message, the $1 variable it's empty.
.bashrc content append of:
preexec() {
if [ "$1" = ";" ]; then
echo "$1 expression evaluated as true"
else
echo "$1 expression evaluated as false"
fi
}
i.e if I type "ls", can something be done in bash-preexec.sh to feed the ouput of "ls" into the invocation of precmd?
I received this bug report for my script which uses the same trickery as bash-preexec:
https://gitlab.com/gnachman/iterm2/issues/3644
It seems that setting a DEBUG trap breaks this use case:
FOO=BAR command something_that_uses_foo.sh
To reproduce with bash-preexec:
echo 'echo $BUILD_SYSTEM' > p
chmod +x p
# Note that this prints "build/core"
BUILD_SYSTEM=build/core command ./p
# Now set up preexec and notice that it breaks
source ~/.bash-preexec.sh
function preexec() {
true
}
# This produces no output
BUILD_SYSTEM=build/core command ./p
This is a problem because it means preexec is incompatible with building Android, and who knows what else. Seems like a bug in bash, but I'm not much of a bash expert myself.
When editing a Bash command you can use Ctrl-x Ctrl-e
to open the command in $EDITOR
, which I have set to Vim. Once I am doing editing the command, i execute :wq
to quit Vim and when I look at my terminal I see __bp_preexec_invoke_exec
being injected into the output.
So for example if I create the command echo foo
in vim then ran it, my output would look like
> echo foo
__bp_preexec_invoke_exec
foo
Any idea why this might be happening and is there a fix?
I am using bash 4.4
When the user ctrl-C at the bash prompt (e.g., begins typing a command, thinks better of it, and presses ctrl-C), the __bp_preexec_invoke_exec() function is invoked, and it finds the previous command from history. I've been unable to find a way for the __bp_preexec_invoke_exec() function to determine if it is invoked because of a command, or because the user hit control-c.
After adopting bash-preexec for a script I maintain, I received a bug report that it changes HISTCONTROL
: https://gitlab.com/gnachman/iterm2/issues/5787#note_34771330
Based on the comment in the code, I think I'd rather preserve HISTCONTROL than get leading and trailing spaces correctly reported (I strip them anyway):
# Remove ignorespace and or replace ignoreboth from HISTCONTROL
# so we can accurately invoke preexec with a command from our
# history even if it starts with a space.
Is the comment accurate? Are there any traps if I remove the call to __bp_adjust_histcontrol? Will anything worse happen than losing some whitespace at the beginning of a command?
I tested it and it seems safe, but I thought I'd check before unleashing this change in prod.
Hey guys,
Sorry if this already exists as an issue / question. I did some googling and read through the issues where and couldn't find a confirmation one way or another.
One thing that I'd like to do is possibly cancel a command altogether if some certain critera is met.
For example, I tried to run git push
and hadn't run my linter yet, then I want it to break and not actually run git push.
Is there any way to handle this within preexec? It looked like the answer might be to hack something around your history and/or traps?
Thanks in advance for any advice on this!
As shown in # 37, enabling extdebug using the shopt utility and return a non-zero status from the preexec function would cause the next simple command to be skipped. Is it possible to abort several simple commands typed into the command line altogether, which are separated by the control operators such as ";"?
For example, if I typed "uptime; df -h", the first command "uptime" is skipped. However, "df -h" still gets executed. Is it possible to also skip the second simple command?
Commands that contain multi-line strings are truncated to the first line. For instance, the following command
echo 'foo
bar'
results in this_command="echo 'foo" being passed to the preexec hooks. The "bar" part is entirely lost. This is because "read" only reads a single line.
Just for curiosity, I wanted to know how is this different than Glyph Lefkowitz’s original version please?
Thanks.
Hi, there is no LICENSE file, which means that:
you retain all rights to your source code and that nobody else may reproduce, distribute, or create derivative works from your work. This might not be what you intend
https://help.github.com/articles/open-source-licensing/
Could you please add a LICENSE file? If you don't really care about how people use the code, choose something permissive like e.g. MIT license
Observed problem: Exiting from tmux
executes all preexec_functions
with the previous command.
Expected behavior: $1
should probably be empty or "logout", since that's what tmux
briefly shows on my screen before exiting.
Steps to reproduce:
$ git -C ~/src/bash-preexec describe --tags
0.3.6
$ tmux -V
tmux 2.6
$ tmux
tmux $ foo() { echo "$@" >> preexec.out; }
tmux $ preexec_functions+=(foo)
tmux $ echo 123
<CTRL + D>
$ cat preexec.out
echo 123
echo 123
If you tail -f preexec.out
while performing these steps, you see that the second echo 123
does indeed come from the <CTRL + D>
.
Whitespace is trimmed from commands. For instance, the command " foo " is recorded as "foo".
This whitespace is stripped when reading the line from the history with the "read" builtin.
Hello,
I'm trying to change my tmux window name on the fly when i'm connecting to another server through SSH.
I tried the following :
preexec() { if [ "$1" == "ssh" ]; then tmux rename-window $3@$1; else tmux rename-window $(whoami)@$(hostname); fi }
After trying ssh myhost -l myuser
Preexec does not seem to be executed ...
Am i missing something ?
Thank you, regards, Greg.
$ source .bash-preexec.sh
$ preexec() { echo "just typed $1"; }
$ date
just typed date
Wed Jun 17 16:20:15 UTC 2015
$ function foo() { echo foo; }
$ foo
just typed foo
foo
$ (date)
Wed Jun 24 02:42:48 UTC 2015
Currently bash-preexec clobbers existing DEBUG traps when it is sourced. Would you be interested in a PR that moves the contents of trap -p DEBUG
into a function and appends it to preexec_functions
?
I run lots of scripts so Ive been wanting bash to update some things once its done.
doing a precmd() { updatestatus -green; echo $?; };
shows that Bash exit status is 0, even if I type false
bash-3.2$ false
0
So I've noticed that every once in a while (it seems random, although maybe we'll discover there's something I'm doing that's causing this problem), my shell will stop updating the prompt (PS1)
I use https://github.com/git/git/blob/master/contrib/completion/git-prompt.sh in order to display git branch information within my prompt and so this is where I usually first notice the issue of precmd
not being executed as I'll switch between branches and find the branch name stays the same. But unfortunately that means the issue could have occurred at some earlier point in time.
Here's my .bashrc so you can see how it's configured
The reason I believe it's precmd
not being triggered, is I adding in an echo
to see what it was doing and I found it was no longer showing the echo and so subsequently I presume no longer calling my prompt
function which sets the PS1.
precmd() { echo 'do stuff'; prompt; }
I've tried unsetting PS1 manually and then setting it again (pretty much as my prompt
function does). I've tried using the reset
command or source ~/.bashrc
and source ~/.bash-preexec.sh
(also tried source ~/.git-prompt.sh
in case that was having issues). But no luck in getting precmd
to start running again.
The only thing I'm able to do is to open a new terminal tab and then move back in the directory I was just in and then close the original tab I had open :-(
Any help you can give me in identifying what part of my bashrc might be causing the issue would be appreciated.
Hello and thank you for you terrifically useful project! 🙂
One simple question regarding usage. Is it possible to do something with the command entered ($1
in preexec
function) before it gets executed by the shell? My practical interest is to append time
to every command, for example.
Thank you for your response in advance and have a good week!
PR #60 regressed the fix to #39. We need to identify a new mechanism to capture traps that avoids the issues discussed there.
As I understand it this is only an issue for users who erroneously export
their PROMPT_COMMAND
at some point in their .bashrc
, so if we can detect that case we could simply not preserve traps for those users.
Hi,
I sent @rcaloras and email (the one on github). Its about something I am working on and is very close in its implementation to this project.
Some users set the bash option "nounset", which makes evaluating "${foo}" an error if there is no variable named "foo". When expanding as a string, "${foo:-}" can be used to explicitly indicate that it is okay for the variable to be unset and use an empty string instead.
This option currently makes bash-preexec fail all over the place, whether set -u is set before or after it is sourced. Unset variables are referenced many times during initialization and hook execution.
Each individual line is mostly easy to fix, but it's a pain to maintain. We cannot set "nounset" in bash-preexec.sh itself, because that would pollute the user's shell options in a potentially very annoying way. However, if we can configure the bats tests to run under "set -u", we should be able to maintain compatibility with this option.
(Preliminary testing indicates that bats 0.4.0 does not support set -u, but bats 1.1.0 from the bats-core fork does. We may have to change the way we install bats on travis for the necessary changes to the test environment to pass.)
It would be nice to also test "set -x", but even bats 1.1.0 does not seem to support that.
The project README.md
clearly states:
It must be the last thing imported in your bash profile.
bash-preexec.sh
itself states:
Sets our trap and __bp_install as part of our PROMPT_COMMAND to install
after our session has started. This allows bash-preexec to be inlucded
at any point in our bash profile.
This comment (which has a typo) seems to contradict the instructions from README.md
.
The README.md
instructions seem more correct; if bash-preexec.sh
is not last, any subsequent changes to PROMPT_COMMAND
will be lost. At the very least, the script comment is misleading.
Additionally, perhaps bash-preexec.sh
could emit a warning if PROMPT_COMMAND
has been modified between __bp_install_after_session_init()
and __bp_install()
? (I spent a while trying to figure out why https://github.com/rupa/z wasn't working on a system where an administrator (unbeknownst to me) included bash-preexec.sh
via a chain of inclusions starting from /etc/bash.bashrc
.)
I'm using FreeBSD 11.2-RELEASE-p8, and the first argument passed to preexec functions is wrong:
153462@davidmandelberg:~$ HISTTIMEFORMAT= builtin history 1 | sed '1 s/^ *[0-9]\+[* ] //'
812 HISTTIMEFORMAT= builtin history 1 | sed '1 s/^ *[0-9]\+[* ] //'
Here are two variations that do work:
153462@davidmandelberg:~$ HISTTIMEFORMAT= builtin history 1 | sed '1 s/^ *[0-9]\{1,\}[* ] //'
HISTTIMEFORMAT= builtin history 1 | sed '1 s/^ *[0-9]\{1,\}[* ] //'
153462@davidmandelberg:~$ HISTTIMEFORMAT= builtin history 1 | sed '1 s/^ *[0-9][0-9]*[* ] //'
HISTTIMEFORMAT= builtin history 1 | sed '1 s/^ *[0-9][0-9]*[* ] //'
Tagging @steinarvk, @d630, and @dimo414 because of #87 and #88.
$ source .bash-preexec.sh
$ preexec() { echo "just typed $1"; }
$ date
Fri Oct 7 11:42:38 BST 2016
Here is my Bash version (installed via Homebrew):
GNU bash, version 4.3.42(1)-release (x86_64-apple-darwin15.4.0)
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Here is the bash location:
/usr/local/bin/bash
I want to display the time spent running a command. I've defined the following functions:
preexec () {
date_before=$(date +%s.%N)
}
precmd () {
if [ -z "$date_before" ]; then
return 0
fi
local date_after
date_after=$(date +%s.%N)
printf "\n%.2fs\n\n" $(bc<<<$date_after-$date_before)
}
On bash version 4.3.33(1)-release (x86_64-apple-darwin14.1.0)
on a mac works as expected. However, on a ubuntu 14.04 version 4.3.11(1)-release (x86_64-pc-linux-gnu)
it doesn't.
It looks like the order of execution on mac is prexec -> precmd
, while on linux is precmd - > preexec
, but even if I swap the function names on linux it still doesn't work as expected.
Also, I've used gdate instead of date on mac. (from coreutils)
Any ideas how to make it work on linux?
After loading bash-preexec.sh, if I launch, for example:
$ ( ls ) &
most of the times, bash exits (not always).
A coworker pointed out that that the fix to #39 doesn't properly preserve the behavior of the DEBUG trap, because preexec only triggers on interactive prompts, whereas before installation the command was triggered on every DEBUG event.
I think this can be fixed by simply moving the old DEBUG trap out of preexec_functions
and instead eval
-ing it at the beginning of __bp_preexec_invoke_exec
- before the short-circuiting checks are made.
The only problem with this is it makes it difficult for someone to clean up the old trap - it's no longer in the trap itself nor in the preexec
/ preexec_functions
, but some other variable. It's simple enough to document that (e.g. "The old DEBUG trap will be preserved in a bp_prior_debug_trap
variable") but that widens the API surface and might be abused.
I'll prepare a patch, but I wanted to get some opinions on the approach first.
As far I can see, we may avoid the DEBUG trap in version 4.4:
PS0
The value of this parameter is expanded (see PROMPTING
below) and displayed by interactive shells after reading
a command and before the command is executed.
PS0 is expanded before DEBUG
When logging out from an Ubuntu ssh session with CTRL+D in an empty command line, the preexec function gets called with the previous "$1" while executing the line /usr/bin/clear_console -q
from ~/.bash_logout
.
For example:
$ ssh localhost
davefx@localhost's password:
Welcome to Ubuntu 16.04 LTS (GNU/Linux 4.4.0-31-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
91 packages can be updated.
0 updates are security updates.
Last login: Mon Jul 25 07:59:53 2016 from 127.0.0.1
davefx@localhost:~ $ preexec() { echo «$1»; sleep 3; }
davefx@localhost:~ $ echo Hello
«echo Hello»
Hello
davefx@laetus:~ $ logout
«echo Hello»
Connection to localhost closed.
davefx@laetus:~ $
(The logout was generated pressing CTRL+D)
I'd like to ship preexec with somethin I'm working on, just to run it in a script.
It doesn't work at all if I source bash-preexec.sh
at the top of the script.
cat my-script.sh
SCRIPTLOCATION="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
source "$SCRIPTLOCATION/bash-preexec.sh"
...
preexec(){
if [[ "$1" == "git"* ]]; then
echo -e "$Blue > $1$reset"
fi
git status
...
}
A very small number of useless commands are ignored by bash-preexec, because they're passed to echo
. E.g., the command line -n
causes bash-preexec to run echo -n
which does not print -n
. The solution I've seen is to use printf '%s\n' ...
instead of echo
.
Hello,
I'm trying to write a helper for certain commands in preexec
, but when certain conditions are met I'd like to completely abort execution of the command.
Is this possible?
Thank you in advance!
Hi,
Every now and then I get the following issue after pressing return on entering a new command:
bash: read: read error: 0: Invalid argument
I'm guessing that this bit of code is causing the issue:
__bp_in_prompt_command() {
local prompt_command_array
IFS=';' read -ra prompt_command_array <<< "$PROMPT_COMMAND"
I have changed the read part to be this:
IFS=';' read -ra prompt_command_array 2>/dev/null <<< "$PROMPT_COMMAND"
and that seems to have squished the message for now. I'll keep an eye on things to see how it goes.
Thanks,
Rich
Several history features should be checked or enabled to make sure bash-preexec can operate correctly.
One example is simply making sure history is turned on.
history_check=$(set -o | grep history)
if [[ "$history_check" == "history off" ]]; then
echo "Enable history to use bash preexec"
return 1
fi;
@rcaloras , thanks.
Could probably add a few more checks to make sure history is properly enabled
Too many checks: history on
, HISTSIZE
, history-size
in ~/.inputrc
...
I vote for auto enabling:)
I've collected some useful settings:
# enable access to the command history
set -o history
# save each line of a multi-line command in the same history entry
shopt -s cmdhist
# save the command with embedded newlines instead of semicolons
shopt -s lithist
# save lines which begin with a space character in the history list
# preserve dups!
HISTCONTROL= # already done
# save all lines in the history list
HISTIGNORE=
# every command being saved on the history list (there is no limit)
HISTSIZE=-1
bind 'set history-size -1'
Some users like to redefine bash builtins, so it's unsafe to use them without saying builtin
first. Here's an issue report where a user had defined an alias for history
and it broke bash-preexec
: https://gitlab.com/gnachman/iterm2/issues/6063
What do you think about replacing the use of history
with builtin history
?
Hi there !
I was just wondering if it was possible to define preexec and precmd functions inside a script so that any information gathered there can be used in a local context.
Thanks in advance
Causes: rcaloras/bashhub-client#27
Looks like both projects leverage the debug trap to create a preexec function. @gnachman any chance you could be convinced to use this library if it can provide everything you need for iTerm2's preexec functionality? I'm happy to make all the PRs :) I want to make sure Bashhub and iTerm2 can work together.
Quoted from #6
I'd love to fix up this project to make it compatible with the awesome iTerm2 :) I wrote bash-preexec to include function arrays and to avoid multiple inclusion which allows multiple shell integrations to add preexec functions triggered through one debug trap hook. Any chance you'd be willing to switch to this library if I make it compatible?
Thanks!
Some users of a project I work on that's based on Bash-Preexec modify their prompt command in ~/.bashrc after sourcing the script. In some cases, we've found they'll do this:
I received the following issue report:
https://gitlab.com/gnachman/iterm2/issues/6398
The internals of __bp_precmd_invoke_cmd
assume IFS
has its default value. I think you could do this:
__bp_precmd_invoke_cmd
, save the current value of IFS
to a local variableIFS
to \t\n
__bp_precmd_invoke_cmd
restore IFS
to the saved value.What do you think?
I run my bash in POSIX mode and noticed that the install step fails due to how trap
is used (see Bash POSIX Mode).
To fix it, I did something like this:
case :$SHELLOPTS: in *:posix:*) posix=1;; esac
if [ "$posix" ]; then pre="set +o posix"; post="set -o posix"; fi
. bash-preexec.sh
PROMPT_COMMAND="$pre
$PROMPT_COMMAND
$post"
Maybe it would be useful to incorporate this into the script.
I received an issue report from a user who had a read-only HISTTIMEFORMAT variable. It caused an error to be printed on every command executed. The issue report is here:
https://gitlab.com/gnachman/iterm2/issues/7028
You can reproduce it by doing
readonly HISTTIMEFORMAT
after loading bash-preexec
, and you get this output on every command:
bash: HISTTIMEFORMAT: readonly variable
I'm not sure if bash lets you detect that the variable is readonly. I suppose the simplest fix would be to redirect the output of the assignment to /dev/null.
Would you mind making a copy of $PIPESTATUS
at the same time as you copy $?
? I don't know of any way to restore PIPESTATUS for each precmd_function, so just having a copy available would be fine.
Steps to reproduce:
Actual result:
Expected result:
Bash -4.4
$
uptime
__bp_preexec_invoke_exec "$_"
14:00 up 12:18, 2 users, load averages: 1.44 1.56 1.58
I believe the 3rd row is unwanted
Thanks!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.