Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

zsh preexec command modification

Tags:

zsh

zsh-zle

Is there a way to modify the command that is about to execute? I would like to redirect the output to a file, as well as print it on the terminal. I found that ls > file.txt | cat does the job, so I would like to add that > file.txt | cat to any command that is about to execute.
Is there a better way to redirect to file and print to terminal? I am trying to make a logger.

like image 667
pvinis Avatar asked Sep 25 '12 10:09

pvinis


2 Answers

You can change the action that is performed when you execute a line to alter the command that will be executed. This can be done by defining a function which you then bind to the enter key.

Lets first define a function that can add the '> file.txt | cat' ending to any command:

function log_and_accept {
    BUFFER="$BUFFER > file.txt | cat"
    zle accept-line
}

The next part is to actually replace the default enter key behaviour with your new function. The default behaviour we are replacing is the accept-line function, and if we look at the zle documentation, you will see that accept-line is bound to ^J and ^M.

To bind this function to those letters you first need to turn it into a widget:

zle -N log_and_accept_widget log_and_accept

Then you can bind it, replacing the old behaviour:

bindkey '^J' log_and_accept_widget
bindkey '^M' log_and_accept_widget

Now you will be expanding that command for every single command you do. Every cd, ls, vim etc etc. As such I recommend that you define a couple more functions that actually turn this on and off:

function turn_on_logging {
    bindkey '^J' log_and_accept_widget
    bindkey '^M' log_and_accept_widget
}
function turn_off_logging {
    bindkey '^J' accept-line
    bindkey '^M' accept-line
}

zle -N turn_on_logging_widget turn_on_logging
zle -N turn_off_logging_widget turn_off_logging

bindkey '^P' turn_on_logging_widget
bindkey '^O' turn_off_logging_widget

I think you should be careful with this. After testing it a little, I quickly grew to dislike it.

like image 94
Matthew Franglen Avatar answered Nov 03 '22 12:11

Matthew Franglen


There are several ways to do that, the 1 I like the most is this block I found here http://git.grml.org/?p=grml-etc-core.git;a=blob_plain;f=etc/zsh/zshrc;hb=HEAD

abk=(
  '...'  '../..'
  '....' '../../..'
  'BG'   '& exit'
  'C'    '| wc -l'
  'G'    '|& grep '${grep_options:+"${grep_options[*]}"}
  'H'    '| head'
  'Hl'   ' --help |& less -r'    #d (Display help in pager)
  'L'    '| less'
  'LL'   '|& less -r'
  'M'    '| most'
  'N'    '&>/dev/null'           #d (No Output)
  'R'    '| tr A-z N-za-m'       #d (ROT13)
  'SL'   '| sort | less'
  'S'    '| sort -u'
  'T'    '| tail'
  'V'    '|& vim -'
  'co'   './configure && make && sudo make install'
  'fc'   '> file.txt | cat'
)

zleiab() {
  emulate -L zsh
  setopt extendedglob
  local MATCH

  if (( NOABBREVIATION > 0 )) ; then
      LBUFFER="${LBUFFER},."
      return 0
  fi

  matched_chars='[.-|_a-zA-Z0-9]#'
  LBUFFER=${LBUFFER%%(#m)[.-|_a-zA-Z0-9]#}
  LBUFFER+=${abk[$MATCH]:-$MATCH}
}

zle -N zleiab && bindkey ",." zleiab

Also notice that I added 'fc' '> file.txt | cat' to the list abk

What this does in that that you type fc after the command and then you hit ,. (comma and period) in rapid succession and zsh will replace fc for > file.txt | cat

like image 22
lmcanavals Avatar answered Nov 03 '22 12:11

lmcanavals