Place command output in shell for further editing

1k views Asked by At

I found a nice zsh command online that uses fzf to fuzzy-search shell history:

fh() {
  eval $( ([ -n "$ZSH_NAME" ] && fc -l 1 || history) | fzf +s --tac | sed 's/ *[0-9]* *//')
}

However, instead of eval-ing the command, I'd like to place it in my prompt and edit it further before running it, something like:

$ fh grep
(search happens)
$ grep -RI foo .  <--- cursor

I tried replacing eval with echo, which is better but doesn't give me the command to edit. Is there a way to do this in bash/zsh?

Here is a related thread with a suggestion to use xvkbd, but I was hoping there is something simpler.

3

There are 3 answers

1
Gronis On BEST ANSWER

You can use the official shell integrations. I use zsh so I just copied the provided script and put it in my ~/.zshrc. This will give you the exact behavior you are looking for, e.g return the command and put the result on the input line, rather than running the command without being able to edit it.

Note: It will override shortcut ctrl+r for history search, instead of putting it into an alias or similar, so maybe not exactly what you want. But maybe you can build a script that works from there.

https://github.com/junegunn/fzf/blob/master/shell/key-bindings.zsh

2
Gairfowl On

In zsh, the vared builtin for the zsh line editor (ZLE) will let you edit an environment variable.
After editing, the updated variable can be used to execute the command:

fh() {
  fzfresult=$( ([ -n "$ZSH_NAME" ] && fc -l 1 || history) | fzf +s --tac | sed 's/ *[0-9]* *//')
  vared -p 'fzfout> ' -ac fzfresult
  ${fzfresult[@]}
}

In the vared command, -p sets the prompt. The -ac option changes the fzfresult variable to an array so we can execute it in the next step.

I don't have fzf installed, so this isn't completely tested, but the result should look like this:

% fh grep
fzfout> grep -RI foo .   <-- edit, hit enter, get output:
file1: text with foo
file4: more text with foobar
0
Josh Friedlander On

I ended up using this:

fh() {
   print -s $( ([ -n "$ZSH_NAME" ] && fc -l 1 || history) | fzf +s --tac | sed 's/ *[0-9]* *//')
}

ie silently print, followed by up-arrow, which brings up the command for editing. Would love to hear if there is a simpler way.