4

I often find that when using the command line, I need to copy a path that appears in the output of the last command. For example I might use find . | grep like this:

[user@localhost /tmp]$ find . | grep B
./directoryAB
./directoryBA
./directoryBB
./directoryBC
./directoryCB

At this point I need to pick up the mouse, copy the path I want, and type cd, then paste. But it would be rad if I could loop over paths in the output and copy the one I want, just using the keyboard. Is there anything that could help me do this?

I use zsh and iTerm2, fwiw.

Raffi
  • 163

3 Answers3

6

It's easier to achieve this with tools that are directly used together with the program that produces the output, instead of trying to scrape it back from what was already printed.

There are tools that can show an interactive "select item" or "select file" prompt and are designed to feed it back into the shell as a command. fzf and broot are two examples.

fzf can accept any input through stdin and let you interactively filter through it, for example:

cd "$(find -type d | fzf)"

This can be wrapped in a shell function, or used as an enhanced Tab-complete (Bash code for this is included with fzf), or even bound to a custom keyboard shortcut, e.g. Alt+D to select a directory via fzf and insert it at cursor position (my aliases.sh has an example for Bash, though it would need to be done very differently for Zsh).

broot on the other hand is specifically a file tree browser, but is also designed to be used through a shell function wrapper.

broot --print-shell-function >> ~/.bashrc

Running the newly created br function will open a file browser, in which you selecting a folder with Alt-Enter will cause the parent shell to cd to the selected location.

grawity
  • 501,077
1

Here's one solution. First, you add these aliases to your .bashrc, .zshrc, or equivalent configuration file:

alias l1='fc -e - | sed -n 1p'
alias l2='fc -e - | sed -n 2p'
alias l3='fc -e - | sed -n 3p'
alias l4='fc -e - | sed -n 4p'
alias l5='fc -e - | sed -n 5p'
alias l6='fc -e - | sed -n 6p'
alias l7='fc -e - | sed -n 7p'
alias l8='fc -e - | sed -n 8p'
alias l9='fc -e - | sed -n 9p'
alias c1='fc -e - | sed -n 1p | tr -d \\n | pbcopy'
alias c2='fc -e - | sed -n 2p | tr -d \\n | pbcopy'
alias c3='fc -e - | sed -n 3p | tr -d \\n | pbcopy'
alias c4='fc -e - | sed -n 4p | tr -d \\n | pbcopy'
alias c5='fc -e - | sed -n 5p | tr -d \\n | pbcopy'
alias c6='fc -e - | sed -n 6p | tr -d \\n | pbcopy'
alias c7='fc -e - | sed -n 7p | tr -d \\n | pbcopy'
alias c8='fc -e - | sed -n 8p | tr -d \\n | pbcopy'
alias c9='fc -e - | sed -n 9p | tr -d \\n | pbcopy'
alias L='fc -e - | nl -b a -w2 -s" "'

Then after you run a command, you can type l1 to just see the first line of the output and c1 to copy it. Type L to see the line numbers. (I'm using aliases because fc -e - doesn't work in a script. I added tr -d \\n so that no newlines are added to the clipboard.)

Note that these aliases re-run the command.

The following solution (mentioned by Miiyr in a comment above) might work better for some people: Select text in iTerm using keyboard


Added later:

You can also use a loop like this:

for i in $(seq 1 500); do
  fc="fc -e - | sed -n ${i}p"
  eval "alias l$i='$fc'"
  eval "alias c$i='$fc | tr -d \\n | pbcopy'"
done
Raffi
  • 163
0

This does the job: https://facebook.github.io/PathPicker/. On a Mac you can do: brew install fpp.

Then for example you can do:

git status
fpp

Use up and down (or j and k) until you find the path you want to edit, then hit enter.

p.s. If you're using tmux with oh-my-tmux (https://github.com/gpakosz/.tmux), prefix F is a shortcut for fpp.

Raffi
  • 163