5

I often need to copy an output line in Bash in its entirety:

$ grep -ilr mysql_connect *
httpdocs/includes/config.php
httpdocs/admin/db.php
statistics/logs/error_log
$ vim httpdocs/includes/config.php

Is there any way to configure a Bash or Tmux shortcut for three lines up, like perhaps @@3:

$ grep -ilr mysql_connect *
httpdocs/includes/config.php
httpdocs/admin/db.php
statistics/logs/error_log
$ vim @@3 # This would be the equivalent of vim httpdocs/includes/config.php (three lines up)

The shortcut does not need to be @@, anything else would do. Ideally this would work in any Bash, but a tmux shortcut would work too.

Note that I am familiar with tmux and screen copy and paste (enter paste mode, move to copy, come back, paste), but I am hoping for something that I could use easier (@@N) as I seem to do this often.

2 Answers 2

1

The following Bash function will use the output you get after running the command (i.e. grep -ilr mysql_connect * ) to create a list from which you can select one option, a file. After selection is made, the file will be opened using Vim.

output_selection()
{
    local i=-1;
    local opts=()
    local s=

    while read -r line; do
        opts+=("$line")
        printf "[$((++i))] %s\n" "$line"
    done < <("$@")

    read -p '#?' s

    if [[ $s = *[!0-9]* ]]; then
        printf '%s\n' "'$s' is not numeric." >&2

    elif (( s < 0 )) || (( s >= ${#opts[@]} )); then
        printf '%s\n' "'$s' is out of bounds." >&2

    else
        vim "${opts[$s]}"
    fi
}

Preconditions: The output must be '\n' delimited.

Usage: output_selection [command]

Example:

output_selection grep '.php$' foo.txt

This is not exactly what you asked for, so you can see that as a legitimate suggestion to perform the same task in a way that is, IMO, more convenient - especially when the output is large.

2
  • Thank you, this is nice and ad-hoc as it can be run as output_selection !! after a command.
    – dotancohen
    Commented Apr 18, 2013 at 9:40
  • You welcome. Please notice that instead of running vim "${opts[@]}" inside the script, you can export a special variable inside your .bashrc, called FOO and then make the script modify this varialbe, i.e. FOO="${opts[@]}". From that point on in your Bash session, you can run [any program you like] "$FOO" Commented Apr 18, 2013 at 12:46
1

Assuming the filenames don't contain spaces, this will do what you asked for:

$ set -- $(grep -ilr mysql_connect * | tac)
$ echo $3
httpdocs/includes/config.php
$ echo $2
httpdocs/admin/db.php
$ echo $1
statistics/logs/error_log

You can create other function without | tac to print it in the right order:

$ set -- $(grep -ilr mysql_connect *)
$ echo $1
httpdocs/includes/config.php
$ echo $2
httpdocs/admin/db.php
$ echo $3
statistics/logs/error_log
1
  • Thank you, this is very nice. Unfortunately it is not quite 'ad-hoc' in the sense that I could run it after any arbitrary query.
    – dotancohen
    Commented Apr 18, 2013 at 9:38

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .