2

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.

  • I can't see any potential whitehat use for what you're asking for.... But, (1) Are you aware of rbash and its purpose? And, (2) Have you considered using aliases or functions for what you're trying to achieve? (What are you trying to achieve, anyway?) – Wildcard Dec 21 '15 at 21:46
  • @Wildcard Thanks but I've already figured a solution which does exactly what I want unix.stackexchange.com/questions/250713/… – VarunAgw Dec 21 '15 at 21:48
  • 1
    @sixtyfootersdude I think you want wildcard about this – VarunAgw Jan 13 '17 at 19:05
  • 1
    @Wildcard - Here is a white hat example of when/how this could be useful: unix.stackexchange.com/questions/337192/… – sixtyfootersdude Jan 13 '17 at 19:09
9

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.
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
0

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.

  • preexec Executed 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.
  • precmd Executed 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:

elementz@Kashmir:~/git/bash-preexec (master)$ ls
just typed ls
bash-preexec.sh  README.md  test
printing the prompt

You 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.

  • Just for anyone else wondering, this is not a built in bash thing. it requires additional installation. Doesn't look like there is yum/apt-get support. – sixtyfootersdude Jan 13 '17 at 17:16
-1

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.