I want to find the age of the oldest file in a certain directory or return 0 if there aren't any files in this directory. I also need a one-line command doing it. So far this is my command for finding the age in seconds of the oldest file in the directory:

expr $(($(date +%s) - $(stat -c %Y $(ls -lt /path/to/dir/ | tail -1 | awk '{print $NF}'))))

The problem is that if there are no files it is returning the following error:

$ expr $(($(date +%s) - $(stat -c %Y $(ls -lt /path/to/dir/ | tail -1 | awk '{print $NF}'))))
stat: cannot stat ‘0’: No such file or directory
-bash: 1554373460 - : syntax error: operand expected (error token is "- ")

So in this case I want the command to return just 0 and to suppress the error printout.

  • 2
    Out of curiosity, why does it have to be in one line? It's much less readable & maintainable that way. – Jeff Schaller Apr 4 '19 at 10:30
  • I am passing this line to specialized software. Then according to the output of the command, I can trigger an alarm and if I make it on more than a single line, I need to write more complex logic. The idea is to check a specific directory where there should not be any files for more than 20 seconds, I want to trigger an alarm if the age of the oldest file is more than 30 seconds. – Georgi Stoyanov Apr 4 '19 at 10:39
  • also I would be very happy if you have any ideas, how I can simplify my command for finding the age of the oldest file – Georgi Stoyanov Apr 4 '19 at 10:41
  • ls -lt | tail -1 will give you the oldest file; you can parse out the date or go through the stat stuff without having to do a single line shell loop – mpez0 Apr 4 '19 at 20:06
  • @mpez0 this is exactly what I am doing, check my original post. – Georgi Stoyanov Apr 5 '19 at 7:52

If it must be one line:

stat -c %Y ./* 2>/dev/null | awk -v d="$(date +%s)" 'BEGIN {m=d} $0 < m {m = $0} END {print d - m}'
  • stat -c %Y ./* 2>/dev/null print the timestamp of all files, ignoring errors (so no files results in no output)
  • With awk:

    • -v d="$(date +%s)" save the current timestamp in a variable d
    • BEGIN {m=d} initialize m to d
    • $0 < m {m = $0} keeping track of the minimum in m
    • END {print d - m} print the difference.
| improve this answer | |
  • unfortunately, it does return 0 no matter if the directory is empty or it has more than one file – Georgi Stoyanov Apr 4 '19 at 10:55
  • @George ah, oops, I inverted the check for min – muru Apr 4 '19 at 11:03

With zsh and perl:

perl -le 'print 0+-M $ARGV[0]' /path/to/dir/*(N-Om[1])

(add the D glob qualifier if you also want to consider hidden files (but not . nor ..)).

Note that for symlinks, that considers the modification time of the file it resolves to. Remove the - in the glob qualifiers to consider the modification time of the symlink instead (and use (lstat$ARGV[0] && -M _) in perl to get the age of the symlink).

That gives the age in days. Multiply by 86400 to get a number of seconds:

perl -le 'print 86400*-M $ARGV[0]' /path/to/dir/*(N-Om[1])
  • (N-Om[1]): glob qualifier:
    • N: turns on nullglob for that glob. So if there's no file in the directory, expands to nothing causing perl's -M to return undef.
    • -: causes next glob qualifiers to apply on the target of symlinks
    • Om: reverse (capital) order by modification time (so from oldest to newest like ls -rt)
    • [1]: select first matching file only
  • -M file: gets the age of the content of the file.
  • 0+ or 86400* force a conversion to number (for the undef case).
| improve this answer | |
  • I am getting just 0 as an output even though it should show me a couple of thousands of seconds, both commands actually gives me the same output and on another machine I am getting an error: -bash: syntax error near unexpected token '(', the one giving me an error is running a rather old version of perl: v5.16.3 – Georgi Stoyanov Apr 4 '19 at 14:39
  • 2
    @GeorgеStoyanov, the syntax is for zsh, not bash. – Stéphane Chazelas Apr 4 '19 at 15:37
  • I missed that part :) Thanks for the answer @Stephane – Georgi Stoyanov Apr 5 '19 at 7:50

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.