Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

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.

share|improve this question
add comment

2 Answers

up vote 1 down vote accepted

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.

share|improve this answer
    
Thank you, this is nice and ad-hoc as it can be run as output_selection !! after a command. –  dotancohen Apr 18 '13 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" –  Rany Albeg Wein Apr 18 '13 at 12:46
    
That is a good idea. Thank you. –  dotancohen Apr 18 '13 at 12:53
add comment

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
share|improve this answer
    
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 Apr 18 '13 at 9:38
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.