0

Okay so I'm using grep on a external HDD

example,

M:/

grep -rhI "bananas" . > out.txt

which would output any lines within " M:/ " containing " bananas "

However I would like to output the entire contents of the file, so if one line in example.txt contains " bananas " output entire content of example.txt and same goes for any other .txt file within directory " M:/ " that contains " bananas ".

2
  • 1
    grep -rnI "bananas" | cut -d: -f1 | xargs cat >> result.txt. Do you need explanation?
    – user996142
    Jun 30, 2017 at 16:43
  • @user996142 yes please explination would be nice :)
    – Jack
    Jun 30, 2017 at 18:10

2 Answers 2

1

grep -r "bananas" | cut -d: -f1 | xargs cat >> result.txt

grep

  • -r: recursive. Read all files under each directory, recursively,

Result: file_name:text for each line. For example foo.txt:bananas.

We now need to fetch file name from each line.

cut Simple editor to remove part of the line (you may use sed or awk here but cut is simple)

  • -d delimiter. Since we have : after file this is our delimiter: -d:
  • -f we splitted our output to fields. Which one to take? -f1 -- first one!

xargs

We now have list of files. That to do with them? We use xargs that builds and executes command lines from standard input. It accepts file name on stdin, and runs cat for each line providing file name as parameter. And cat simply prints its contents to stdout.

>> means "append to file"

1
  • Thank you +1 ( sorry I can't tick you answer as i'm a guest )
    – Jack
    Jun 30, 2017 at 20:07
1
grep -rlZI "bananas" . | xargs -0 cat > out.txt

The -lZ outputs a null-separated list of the names of matching files:

-l, --files-with-matches
       Suppress normal output; instead print the  name  of  each  input
       file  from  which  output would normally have been printed.  The
       scanning will stop on the first match.

-Z, --null
       Output a zero byte (the ASCII  NUL  character)  instead  of  the
       character  that normally follows a file name.  For example, grep
       -lZ outputs a zero byte after each  file  name  instead  of  the
       usual  newline.   This option makes the output unambiguous, even
       in the presence of file names containing unusual characters like
       newlines.   This  option  can  be  used  with commands like find
       -print0, perl -0, sort -z, and xargs  -0  to  process  arbitrary
       file names, even those that contain newline characters.

If your version of grep doen't provide the -Z option, then you can fall back to plain -l which will still handle filenames containing whitespace (excluding newlines obviously) provided you set the xargs delimiter to newline as well:

grep -rlI "bananas" . | xargs -d '\n' cat > out.txt
1
  • Thank you +1 ( sorry I can't tick you answer as i'm a guest )
    – Jack
    Jun 30, 2017 at 20:07

You must log in to answer this question.

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