I am trying to create a program which require such feature. The flow will be like:
- User enter a bash command
- User hit the enter
- My script will get command, current directory,.. as variables. Program can optionally modify the command.
- Modified command will get executed normally.
Is there any way to do this?
Note: I need this for my personal use, I am not going to distribute this program.
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
I did some research on it. We can use bash TRAP and shopt option to achieve this.
Add this to .bash_profile
shopt -s extdebug
preexec_invoke_exec () {
[ -n "$COMP_LINE" ] && return # do nothing if completing
[ "$BASH_COMMAND" = "$PROMPT_COMMAND" ] && return # don't cause a preexec for $PROMPT_COMMAND
local this_command=`HISTTIMEFORMAT= history 1 | sed -e "s/^[ ]*[0-9]*[ ]*//"`;
# So that you don't get locked accidentally
if [ "shopt -u extdebug" == "$this_command" ]; then
return 0
fi
# Modify $this_command and then execute it
return 1 # This prevent executing of original command
}
trap 'preexec_invoke_exec' DEBUG
It works like this:
trap 'function_name' DEBUG causes function_name to execute before executing bash commands. But by default return value have no effect over original command.
shopt -s extdebug enables some debugging features with one of them checks for return value before executing original command.
Note: shopt -u extdebug disable this feature so original command always get executed.
Documentation of extdebug (See second feature):
If set, behavior intended for use by debuggers is enabled: The -F option to the declare builtin (see Bash Builtins) displays the source file name and line number corresponding to each function name supplied as an argument. If the command run by the DEBUG trap returns a non-zero value, the next command is skipped and not executed. If the command run by the DEBUG trap returns a value of 2, and the shell is executing in a subroutine (a shell function or a shell script executed by the . or source builtins), a call to return is simulated. BASH_ARGC and BASH_ARGV are updated as described in their descriptions (see Bash Variables). Function tracing is enabled: command substitution, shell functions, and subshells invoked with ( command ) inherit the DEBUG and RETURN traps. Error tracing is enabled: command substitution, shell functions, and subshells invoked with ( command ) inherit the ERR trap.
Method 2
You can get some way towards your goal with a simple bash script that uses the built-in readline system to get a line. For example:
#!/bin/bash -i
while read -e -p '$ ' line
do echo "your cmd: $line"
eval "$line"
done
The script reads a line of input (unless end-of-file) using readline editing (-e) and then echoes and executes it. Note the -i on the #! to ensure the script is interactive. You can build your code to manipulate the input command based on this. For example,
#!/bin/bash -i
myfn(){
echo "in dir $1. doing: $2" >&2
echo "$2" # manipulate command here and echo the result
}
while read -e -p "$PS1" line
do newcmd=$(myfn "$PWD" "$line")
eval "$newcmd"
done
Method 3
Install bash-preexec – preexec and precmd functions for Bash just like Zsh
Two functions preexec and precmd can now be defined and they’ll be automatically invoked by bash-preexec if they exist.
preexecExecuted just after a command has been read and is about to be executed. The string that the user typed is passed as the first
argument.precmdExecuted just before each prompt. Equivalent to PROMPT_COMMAND, but more flexible and resilient..
source ~/.bash-preexec.sh preexec() { echo "just typed $1"; } precmd() { echo "printing the prompt"; }Should output something like:
<a href="https://getridbug.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="76131a131b1318020c363d17051e1b1f04">[email protected]</a>:~/git/bash-preexec (master)$ ls just typed ls bash-preexec.sh README.md test printing the promptYou can also define functions to be invoked by appending them to two different arrays. This is great if you want to have many functions invoked for either hook.
Method 4
In any shell script, the currently executing command is available as $0, and the current directory can be easily retrieved with a call to pwd. In order to do what you want, you will have to write a program that can be used as a shell, and then set your user’s shell value to that program.
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0