4

How can I perform a grep on only the 'tail' of a file?

I am trying to run this command:

grep 'TEST COMPLETE' -L *.log

TEST COMPLETE appears in the last couple lines, this command lists all the files in the folder that have not yet finished the test (Because of -L). The logs are very big though so grep is very slow.

On the other hand I can pipe grep on the tail. The grep is pretty much instant:

tail *.log | grep 'TEST COMPLETE'

However I cannot use the -l or -L arguments as I am now grepping the pipe input and not a file. So running it with the list files argument:

tail *.log | grep 'TEST COMPLETE' -L

Will just output: (standard input)

Is there any way I can just get grep to search on the last 10 lines or something like that?

  • Are you REALLY running tail on multiple log files at once as we're all assuming or are you actually just running it on 1 log file but used `*.log` to avoid making up a name for the file? – Ed Morton Apr 17 '19 at 21:52
  • Yes. Running it on too many files to be able to sift through this manually. If it was just one file I wouldn't need this command as I can just do `tail file.log` and see if it is complete. – Winter Is Overflowing Apr 18 '19 at 15:14

4 Answers4

6

You can just do it in a for loop:

for log in *.log; do
   if ! tail "$log" | grep -q 'TEST COMPLETE'; then
      echo "$log"
   fi
done
Mike Holt
  • 4,452
  • 1
  • 17
  • 24
  • That works thank you! Is there any purpose for quoting the variables? – Winter Is Overflowing Apr 18 '19 at 15:11
  • 1
    [When to wrap quotes around a shell variable?](https://stackoverflow.com/questions/10067266/when-to-wrap-quotes-around-a-shell-variable) – Mike Holt Apr 18 '19 at 17:48
  • The accepted answer in that referenced question has the thought process backwards - quotes aren't something you **add** when you need to, they're something you **remove** when you need to. Always wrap strings and scripts in single quotes unless you **need** to use double quotes (e.g. to let a variable expand) or **need** to use no quotes (e.g. to do globbing and file name expansion). [@tripleee's answer](https://stackoverflow.com/a/27701642/1745001) to that question is better but see also https://mywiki.wooledge.org/Quotes – Ed Morton Apr 19 '19 at 00:13
2

This should work:

for f in *.log; do  tail "$f" | grep -q 'TEST COMPLETE' || echo "$f"; done
HardcoreHenry
  • 5,909
  • 2
  • 19
  • 44
  • I'm not the one who downvoted, but I would guess that it's because you have the logic inverted. OP wants to print out the names of files that *don't* contain `TEST COMPLETE`. But yeah, your answer is basically the same as mine if you change the `&&` to `||`, and quote the `$f`. This should have been a comment, not a downvote. – Mike Holt Apr 17 '19 at 19:04
0

Assuming tail *.log puts ==> filename <== between each file and that string doesn't occur in any of the files:

tail *.log |
awk 'gsub(/^==> | <==$/,""){if (f) print f; f=""} /TEST COMPLETE/{f=FILENAME} END{if (f) print f}'
Ed Morton
  • 188,023
  • 17
  • 78
  • 185
-2

tail -n10 FILENAME Will give you the last 10 lines of the file. You can then pipe this into grep as done in your question.