7

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?

3 Answers 3

9

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)"
7
  • 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
    Commented May 13, 2016 at 2:32
  • @DopeGhoti: You find that ls dir and ls dir/ do different things?  Not for me. Commented May 13, 2016 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
    Commented May 13, 2016 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
    Commented May 13, 2016 at 13:11
  • 1
    Clever and efficient... +1 for using only grep and not find or xargs. Commented Feb 16, 2021 at 1:49
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.

3
  • 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
    Commented May 13, 2016 at 14:57
  • @cas - that will probably never happen (and for good reason imo). Commented May 13, 2016 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
    Commented May 13, 2016 at 22:54
1

With zsh:

grep string /var/log/**/*(.om)

With the om qualifier, the files are ordered by modification time, from youngest to oldest like with ls -t. . is to restrict the match to regular files. You can add m-1 to restrict to files last modified in the last day or mh-1 in the last hour, etc.

If /var/log has directories that are symlinks to elsewhere and you want them followed (like find find -L / find -follow), you can replace **/ with ***/.

To stop after the first file with matches has been found, you could use gawk as:

gawk '/string/ {print FILENAME": "$0; found++}
      ENDFILE  {if (found) exit}' /var/log/**/*(.om)

You must log in to answer this question.

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