Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use preexec() to evaluate entered command

Tags:

zsh

I want to use preexec() to modify certain commands before they are run but I need to be able to evaluate the current entered command. Is there a variable that contains the entire command before it is executed? I know !! is the last command but I need the current line before it's saved to history.

An example of what I want to do would probably help

ls -l /root please

And then I want preexec to see I wrote "please" at the end and replace it with

sudo ls -l /root

I think something like

preexec() {
    if [[ $CURRENT_LINE =~ please$ ]]; then
        $CURRENT_LINE="sudo ${CURRENT_LINE% please}"
    fi

Would work but I can't find a variable in zsh that gives me the correct $CURRENT_LINE

For bonus points I also want to be able to enter please on a line by itself and have it run sudo !! but I could probably do that with some form of alias.

I think it might be better to make a please function that I can pipe a command to but I don't think that'll work as well because the command will run and fail (before piping) before it is run again with sudo.

like image 637
Justin Garrison Avatar asked Jan 22 '15 22:01

Justin Garrison


1 Answers

As far as I know that the preexec is not for the right place to modify the command to be executed though. We can not change the commands to be executed from inside of the preexec function…

Although the actual command to be executed are passed as $1, $2 and $3.

preexec

Executed just after a command has been read and is about to be executed. If the history mechanism is active (and the line was not 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.

-- zshmisc(1) 9.3.1 Hook Functions

For example:

alias ls='ls -sF --color=auto'
preexec () { 
  print ">>>preexec<<<"
  print -l ${(qqq)@}
}

If I have above in ~/.zshrc then I will get follows:

% echo test preexec<Esc-Return>
ls<Return>
;# outputs below
>>>preexec<<<
"echo test preexec
ls"
"echo test preexec; ls -sF --color=auto"
"echo test preexec
ls -sF --color=auto"
test preexec
total 1692
...

You could add your own zle widget functions to the zsh line editor for manipulating the line editor buffer. (zshzle(1))

You could add the zle widget function to change the behavior for hitting Enter.

my-accept-line () {
  if [[ "$BUFFER" == *" please" ]]; then
    BUFFER="sudo ${BUFFER% please}"
  fi
  zle .accept-line
}
zle -N accept-line my-accept-line

The above snippets changes the functionality for accept-line from the built-in behavior to my-accept-line defined here.


Adding the abbreviations also could help which is described below:

Cloning vim's abbreviation feature

-- “examples:zleiab [ZshWiki]” - http://zshwiki.org/home/examples/zleiab

like image 78
hchbaw Avatar answered Nov 10 '22 09:11

hchbaw