I have an application which generates a couple of files in different directories at a regular interval and I need to check the latest files generated, I.e. the file which is generated in the most recent directory (created or updated). The name of the file remains the same in all directories, so I just want a simple script which will change the directory to the last modified subdirectory.

[Update] By seeing most of the answers, I think I should clarify that the directory names are dynamic (depends upon some user input & timestamp), so I can't assume a directory pattern like dir[1, 2, 3] or similar

4 Answers 4


You don't need any elaborate pipelines for this. Moreover, you don't need to find anything - you already know where each file is, you just don't know which of them is newest. This is easily handled.

To demo, here's my little test:

mkdir ./dir1 ./dir2 ./dir3

for d in 1 2 3
do  touch ./dir$d/samefile
    sleep 1

That creates the test set. Now, which is newest?

set -- ./dir[123]/samefile
while [ -e "$2" ]
do  [ "$1" -nt "$2" ] && 
    set -- "$@" "$1"
shift; done
printf %s\\n "$@"

That will tell me.



And I can switch around the order of the touch operation as much as I like - it'll give me the right information. All you need is that tiny little shell loop in a function like this:

newd() { ${2:+:} return 1
    while [ -e "$2" ] && [ -e "$1" ]
    do  [ "$1" -nt "$2" ] && 
        set -- "$@" "$1"
    shift; done
    ${2+false} cd "${1%/*}"

Note that this is a little different than the demo so it will reliably fail given fewer than two arguments or if any argument is not an actual pathname.

Now you can call it like:

newd ./path/to/file1 ./path/to/file2

...and so on - with as many arguments as you like.

Or, in my test case:

newd ./dir[123]/samefile ; pwd



Depending on what you want exactly to do, and the structure of your files, other possibilites may be available, such as :

ls -1tq /dir/*/readme.txt | head -n 1

Returns the full name of the most recent readme.txt found in any subdirectory (not recursive) of /dir/

The usage of * as part of the path (not just as part of a filename) often being underknown, I thought it was worth mentioning it.

file=$( ls -1tq /dir/*/readme.txt | head -n 1 )
cd $( dirname "$file" )
  • It would be a little safer to use ls -1tq, but that still has problems with spaces in file names if it matters, and globs in that way need validation... But all of that is for edge cases, anyway. Still - how do you cd to it? You might wanna put it in a $(command sub)?
    – mikeserv
    Commented Jul 29, 2014 at 10:40
  • That was more a way to open the possibilities : maybe he has concluded he had to change directory, without being strictly necessary. But you're right : you can still make things like cd $( ls -1t /dir/*/readme.txt | head | basename ) Commented Jul 29, 2014 at 11:37
  • answer edited to reflect these thoughts Commented Jul 29, 2014 at 11:43
  • @Pierre-OlivierVares thanks for the answer. This definitely helps and serves the purpose.
    – Jay
    Commented Jul 30, 2014 at 9:21

For more portability, you can use perl:

$ perl -MList::Util=reduce -le '
    BEGIN { $dir = "." }
    opendir DIR,$dir;
    print shift @{(reduce {$a->[1] > $b->[1] ? $a : $b}
                   map {[$_,(stat($_))[9]]}
                   grep { -d and !/^..?$/ }
                   readdir DIR)}

Change $dir to whatever directory you want to search.

How does it work

  • readdir return list of all files and directory in dir handle open by opendir
  • grep { -d and !/^..?$/ }: we get all directory, skip . and .. directory.
  • map {[$_,(stat($_))[9]]}: creat an array, its element is a array reference with two elements:
    • First is directory name
    • Second is modified time
  • reduce {$a->[1] > $b->[1] ? $a : $b: like a max function, we compare each element in array by the second element, which is the modified time.
  • @{...} de-reference the array, shift get the first element, which is directory name.
  • What does Skype do?
    – mikeserv
    Commented Jul 29, 2014 at 10:30
  • 1
    @mikeserv: oh, it's the result return in my current working directory.
    – cuonglm
    Commented Jul 29, 2014 at 10:32
  • Cool. well done.
    – mikeserv
    Commented Jul 29, 2014 at 10:35
  • @Gnouc thanks for the alternate perl script, but I like the one line bash command line for this matter.
    – Jay
    Commented Jul 30, 2014 at 9:25
  • @Jay: one line bash in this case is more difficult and less portable. You can call this perl directly in your bash script. If you only want bash, try @mikeserv's newd() function.
    – cuonglm
    Commented Jul 30, 2014 at 9:27

Short answer: look into man find and the 'time' options. This will locate the file(s), then use the -printf option to display the path of the file(s), which then can be used for cd <path>

One way to use find and extract DIR of the last accessed file (within the last 24h) in current dir and its sub directories

lastAccDir="$(find 2>/dev/null . -type f -atime 1 -printf "%a~%h\n" | sort -r | head -n 1 | cut -d~ -f2)"

or the same with line continuation (more readable)

find 2>/dev/null . -type f \ -atime 1 -printf "%a~%h\n" \
 | sort -r \
 | head -n 1 \
 | cut -d~ -f2

Note that this MAY result in an empty result due to -atime 1 (last 24h)

test ! -z "$lastAccDir" && cd "$lastAccDir"
then checks for non-empty result and moves into the dir if not empty.


You must log in to answer this question.

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