3

I have a need to search a certain folder for the newest created file and grep the contents for a pattern. I have had ok success so far using this command:

find /var/log/folder -type f -printf '%T+ %p\n' | sort | tail -n1 | xargs grep 'string to find'

This does find the latest file that has the match but I am getting an unexpected line in stdout.

$ find /var/log/folder -type f -printf '%T+ %p\n' |   sort | tail -n1 | xargs grep 'string to find'
grep: 2016-05-12+20:01:59.0570667340: No such file or directory
/var/log/folder/file:string to find

How can I change my command so it does not give me the "no such file or directory" line?

4

Here is a version that is safe for names with whitespace:

find /var/log/folder -type f -printf '%T@ %p\0' | sort -rz | sed -Ezn '1s/[^ ]* //p' | xargs --null grep string

How it works:

  • find /var/log/folder -type f -printf '%T@ %p\0'

    This looks for files and prints their modification time (seconds) followed by a space and their name followed by a nul character.

  • sort -rz

    This sorts the null-separated data.

  • sed -Ezn '1s/[^ ]* //p'

    sed -z handles nul-character delimited lines and this prints just the name of the newest file

  • xargs --null grep string

    This reads the null-separated file name and greps the string.

  • GNU ls really needs a -0 or other NUL-delimiter option, like many other GNU tools (including head and tail) have gained over the last decade or so....it's starting to become surprising when you find a GNU tool that doesn't have one yet. – cas May 13 '16 at 14:57
  • @cas - that will probably never happen (and for good reason imo). – don_crissti May 13 '16 at 22:07
  • It still would be nice to have a tool that offered ease of use, like ls or ls -rt, but that you could count on to work reliably with modern file names. – John1024 May 13 '16 at 22:54
4

ls -1rt /path/to/files/ | tail -n1 will find the newest file in a directory (in terms of modification time); pass that as an argument to grep:

grep 'string to find' "$(ls -1rt /path/to/files/ | tail -n1)"
  • using -1art was returning "grep: .: Is a directory". I changed it to "ls -Art" and it works perfectly. So why was ls -1art was not working as expected? – user53029 May 13 '16 at 2:32
  • @DopeGhoti: You find that ls dir and ls dir/ do different things?  Not for me. – G-Man Says 'Reinstate Monica' May 13 '16 at 3:20
  • I do when I'm sleep-deprived and actually thinking of rsync and not ls. The problem was that I had -a in my answer which was including . and .., which might end up being the most recently changed thing in a directory. – DopeGhoti May 13 '16 at 3:31
  • Ok I have a problem. This works but I have to be inside the folder where the ls is ran. If the command specifies an absolute path, why do I have to be inside that folder for it to work? – user53029 May 13 '16 at 13:11
  • You can exclude directories with ls's -p option (which appends a '/' to directory names) and piping into grep -v '/$' before piping into tail -n 1. This works with at least GNU and FreeBSD's versions of ls. – cas May 13 '16 at 15:03

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.