4

I know that

grep -rhI "# Active" > out.txt 

will output any line containing # Active within the searched directory but I want the entire .txt file contents, so example

example.txt

Line1 
Line2
Line3 # Active
Line4
Line5
etc

So if I grep for # Active I want it to not just output the line containing # Active within these .txt file but all the other lines too, example

output.txt

Line1 
Line2
Line3 # Active
Line4
Line5
etc
  • 1
    Maybe you can try to use -C (context) switch for grep. Not ideal (need to know maximum lines in file), but helps. – Marius Karnauskas Nov 23 '17 at 22:39
  • 1
    What kind of line separator do you have between your lines? Windows (#10#13) or UNIX newlines (#13)? Maybe the whole file is treated as one line but displayed on multiple lines. – Dominique Nov 24 '17 at 8:46
12

For non-GNU versions of grep, which are unlikely to have -z, or if portability is required...

grep -q pattern file && cat file

-q suppresses any output but, per usual, exit status is set based on whether or not a pattern match was found. With a pattern match grep returns the success code 0 which is equivalent to true and that allows the cat command to be executed.

  • a variant : grep -l "pattern" ./file*s | xargs cat . displays the (concatenated) entirety of all files that have at least 1 line matching "pattern" – Olivier Dulac Nov 24 '17 at 12:12
8

Normally, grep will just show the matching line:

$ grep -rhI "# Active"
Line3 # Active

To see the whole file, add the -z flag:

$ grep -rhIz "# Active"
Line1 
Line2
Line3 # Active
Line4
Line5
etc

-z is a GNU extension that tells grep not to use newline as the 'line' separator but to use a NUL character instead. Since text files generally do not have NUL characters in them, this has the effect of telling grep to read the whole file as if it were a single 'line'. Consequently, if there is a match, the whole file is printed.

On BSD/OSX versions of grep, the NUL input option is not available and -z means something else.

The other grep options

-r tells grep to search files and directories recursively.

-I tells grep to ignore binary files

-h tells grep to print the match without the filename attached.

3

sed alternative:

sed -e 'H;1h;/PATTERN/!d;x;:do' -e 'n;b do' infile

this script works by accumulating lines in the hold buffer (and deleting them) until a matching line is encountered at which point it exchanges the buffers and executes n (i.e. print & get the next line) until there's no more input.

1

If you want to do it on multiple files:

cat `grep -rIl "# Active" *`

Grep will return the list of filenames and cat will print them.

  • 2
    and pray that none of those paths contains spaces or other funky chars... – don_crissti Nov 24 '17 at 17:48
  • True, but this is the only way I see to do it with multiple files. If you have a solution to the "funky chars" feel free to edit my answer. – ChatterOne Nov 24 '17 at 21:35
  • There are too many ways to do it right: use a for loop, use find with -exec, use grep with -Z and pipe it to xargs -0 cat, use zsh with estring qualifier etc... – don_crissti Nov 24 '17 at 21:49
  • shopt -s globstar ; for file in **/*; do test -f "$file" && grep -qlF '# Active' "$file" && cat "$file"; done – Hauke Laging Nov 24 '17 at 21:59
  • @don_crissti As I said, feel free to edit my answer – ChatterOne Nov 25 '17 at 20:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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