0

I have bunch of files in a directory.

# ls -1
file1
file2
file3
file4
file5
file6
file7
file8
file9
file10

Task is to find files older than file5. which I can do like

# find . ! -newer file5
./file1
./file2
./file3
./file4
./file5

now I have a file in which reference for any/all of above could be like

# logfile=log
cat ${logfile}
/var/log/app/file1
/var/log/app/file3
/var/log/app/file5

now I want list of only those files that are older than file5 & are also in logfile. so the resulting list would be:

file1
file3
file5

I tried greping filenames from these like this but it doesn't work.

find . ! -newer file4 -exec bash -c 'for i in {}; do grep $i ${logfile}; done' \;
Sollosa
  • 1,929
  • 4
  • 20
  • 38

1 Answers1

2

If the directory is /var/log/app then instead of find . ! -newer file5 run find /var/log/app ! -newer /var/log/app/file5. This way the output of find will be in the general format you have in the log.

Then you can filter the output of find with just one grep:

find /var/log/app ! -newer /var/log/app/file5 | grep -xFf log

-x causes grep to match whole lines; -F tells it to treat patterns as fixed strings; -f reads patterns from the specified file. These options are portable.

Alternatively (or in a case when the current working directory is not /var/log/app, yet you want to pretend it is) create a second log, so entries in it match the general ./… format of your original find:

sed 's|^/var/log/app/|./|' log > log2

The new log contains relative paths that can be used to filter the output of your original find command:

find . ! -newer file5 | grep -xFf log2

Notes:

  • ! -newer file5 does not mean "older than file5". This test matches file5 and any equally old file.
  • Additional options/tests (e.g. -maxdepth 1, -type f) may be useful.

Your try:

find . ! -newer file5 -exec bash -c 'for i in {}; do grep $i ${logfile}; done' \;

is flawed or sub-optimal in many aspects:

  • You're treating the logfile as data, the pathnames from find as patterns. As shown above, it's way easier to do this the other way around.
  • In the context of the inner bash, $i and ${logfile} are not quoted. They should be double-quoted
  • You embedded {} in the shell code. In general embedded {} can behave like an unquoted variable, but no matter how you quote it, there is command injection vulnerability. So it's even worse.
  • You used -exec … \; which substitutes {} with one pathname (as opposed to -exec … {} +), still you wrote for i in {} as if you expected many. In general the inner shell may interpret what it got in place of {} as multiple words. Filename generation may also be triggered. This is "like an unquoted variable" behavior mentioned above. So in general you may get many "pathnames" for the loop, just not what you expect.
  • logfile is not in the environment, so the inner shell will expand $logfile to an empty string. You don't want the outer shell to expand it (making it so would be similarly flawed as embedding {}).