简体   繁体   中英

Why does this git/grep/vim shortcut bash code not work as advertised?

At the end of this bash tutorial video link ,Spencer Krum shows a neat hack: how to open a file in vim at the line number where an immediately preceding 'git grep -n' search string was located. It seemed neat, but his code does not work as described on two different linux boxes I tried it with. It just always opens a blank file. original code here

My steps:

First, I made sure to have git initialized and files inside the directory to grep for. For example, I had a somefile.txt with three lines of words:

  • its
  • a
  • mystery

Then I ran: git init;git add.; git commit git init;git add.; git commit

Then, modify your.bashrc file to redefine vim as shown below. Make sure to source the.bashrc file when complete: source ~/.bashrc

Finally, run the git grep -n command with a search term you know is in a file in your git directory that is your current working directory. Finally, run vim. It should open your file with the cursor at the search term line. But it doesn't: git grep -n mystery;vim

#Spencers Original
vim () {
    last_command=$(history | tail -n 2 | head -n 1)
    if [[ $last_command =~ 'git grep' ]] && [[ "$*" =~ :[0-9]+:$ ]]; then
        line_number=$(echo $* | awk -F: '{print $(NF-1)}')
        /usr/bin/vim +${line_number} ${*%:${line_number}:}
    else
        /usr/bin/vim "$@"
    fi
}

To get the desired result, I had to simplify the regex in the second clause of the first if statement, and also create some temp variables to run additional eval logic on.

Below is my revised code:

#My revised version
vim () { 
    last_command=$(history | tail -n 2 | head -n 1)

    rempws="${last_command#*"  "}"
    remtws="${rempws%*" "}"

    file_name="$(eval $remtws | awk -F: '{print $(NF-2)}')"
    line_number="$(eval $remtws | awk -F: '{print $(NF-1)}')"

    if [[ $last_command =~ 'git grep' ]] && [[ $line_number =~ [0-9] ]]
    then
        /usr/bin/vim +${line_number} ${file_name}
    else
        /usr/bin/vim "$@"
    fi
}

Is this related to a bash update since 2015? I don't think it's git related, as my git grep -n command does return a string in the form 'somefile.txt:3:mystery'. Everybody in the audience loved it, and it's still on github on the non-functioning form, so I am worried that I am missing something fundamental about bash.

Show me why I'm dumb.

Ok, I finally understood what this is about.

His code was never really meant to somehow access the output of the git grep command.

Instead, it's a realization that after a git grep you're likely to want to open one of the results.

But, in his workflow, he still relies on copy & paste of the git grep results into the Vim command-line.

The only difference is that, right after a git grep , you can pass Vim a filename with a line number separated by : rather than having to pass two separate arguments.

In his example, the result of git grep started with:

CHANGELOG.rst:75: ...

So, if at the next command you execute:

$ vim CHANGELOG.rst:75:

(Assuming you copied the last part from the git grep results.)

Then the bash function would trigger this command instead:

$ vim +75 CHANGELOG.rst

Which will open this file on line 75.

If you like the idea of this feature, a much cleaner way to implement that is to install and enable the bogado/file-line Vim plug-in, which implements support for that kind of filename + line number arguments in Vim itself.

(Also, there's really no good reason to only recognize the file:line syntax right after a git grep . If you want that behavior, it's better to always get it, not just sometimes. It should be consistent.)

An even better alternative is to use the quickfix feature of Vim, which was conceived for exactly this kind of situation. You can either set 'grepprg' manually, to invoke git grep with the appropriate arguments, or you can adopt a plug-in such as vim-fugitive , which implements a :Ggrep command that calls git grep and presents the results using the quickfix list.

As pointed out by @romainl, you might also want to look into git jump , which is a git command you can enable on your system to have git find interesting locations (such as git grep or git diff output) and have git itself open those results in Vim (using the quickfix list when appropriate.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM