0

Grep output is usually like this:

after/ftplugin/python.vim:49:  setlocal number

Is it possible for me extract the file name and line number from this result using standard linux utilities ? Looking for a generic solution that works pretty well .

I can think of using awk to get the first string like :

Input

echo 'after/ftplugin/python.vim:49:  setlocal number' | awk 'print $1' 
'after/ftplugin/python.vim:49:'
$

Expected

after/ftplugin/python.vim and 49

Goal : Open in Vim

I am writing a small function that transforms the grep output to something vim can understand - mostly for academic purpose . I know there are thinks like Ack.vim out there which does something similar . What are the standard light weight utils out there ?

Edit: grep -n "text to find" file.ext |cut -f1 -d: seems to do it if you dont mind double parsing the string . Sed though needs to be used !

4 Answers 4

2

If you're using Bash you can do it this way:

IFS=: read FILE NUM __ < <(exec grep -Hn "string to find" file)
vim "+$NUM" "$FILE"

Or POSIX:

IFS=: read FILE NUM __ <<EOD
$(grep -Hn "string to find" file)
EOD
vim "+$NUM" "$FILE"

Style © konsolebox :)

Sign up to request clarification or add additional context in comments.

Comments

2

This will do:

echo 'after/ftplugin/python.vim:49:  setlocal number' | awk -F: '{print $1,"and",$2}'
after/ftplugin/python.vim and 49

But give us data before grep. It may be that we can cut it more down. No need for both grep and awk

Comments

1

If by "reverse parse" you mean you want to start from the end (and can safely assume that the file content contains no colons), parameter expansion makes that easy:

line='after/ftplugin/python.vim:49:  setlocal number'
name_and_lineno=${line%:*}
name=${name_and_lineno%:*}
lineno=${name_and_lineno##*:}

Being all in-process (using shell built-in functionality), this is much faster than using external tools such as sed, awk, etc.

To connect it all together, consider a loop such as the following:

while read -r line; do
  ...
done < <(grep ...)

Now, to handle all possible filenames (including ones with colons) and all possible content (including strings with colons), you need a grep with GNU extensions:

while IFS='' read -u 4 -r -d '' file \
          && read -u 4 -r -d ':' lineno \
          && read -u 4 -r line; do
  vim "+$lineno" "$file"
done 4< <(grep -HnZ -e "string to find" /dev/null file)

This works as follows:

  • Use grep -Z (a GNU extension) to terminate each filename with a NUL rather than a :
  • Use IFS='' read -r -d '' to read until the first NUL when reading filenames
  • Use read -r -d ':' lineno to read until a colon when reading line numbers
  • Read until the next newline when reading lines
  • Redirect contents on FD #4 to avoid overriding stdin, stdout or stderr (so vim will still work properly)
  • Use the -u 4 argument on all calls to read to handle contents from FD #4

Comments

1

How about this?:

echo 'after/ftplugin/python.vim:49:  setlocal number' | cut -d: -f1-2 | sed -e 's/:/ and /'

Result:

after/ftplugin/python.vim and 49

1 Comment

Works but it it possible to assign to a variable and pass it back to Vim - any thoughts ? "And" was not meant literally actually . Also it breaks when extra : is there in the filename . Need to reverse parse it .

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.