Get the newest directory to a variable in Bash

This ia a pure Bash solution:

topdir=/backups
BACKUPDIR=

# Handle subdirectories beginning with '.', and empty $topdir
shopt -s dotglob nullglob

for file in "$topdir"/* ; do
    [[ -L $file || ! -d $file ]] && continue
    [[ -z $BACKUPDIR || $file -nt $BACKUPDIR ]] && BACKUPDIR=$file
done

printf 'BACKUPDIR=%q\n' "$BACKUPDIR"

It skips symlinks, including symlinks to directories, which may or may not be the right thing to do. It skips other non-directories. It handles directories whose names contain any characters, including newlines and leading dots.


BACKUPDIR=$(ls -td /backups/*/ | head -1)

$(...) evaluates the statement in a subshell and returns the output.


There is a simple solution to this using only ls:

BACKUPDIR=$(ls -td /backups/*/ | head -1)
  • -t orders by time (latest first)
  • -d only lists items from this folder
  • */ only lists directories
  • head -1 returns the first item

I didn't know about */ until I found Listing only directories using ls in bash: An examination.


Well, I think this solution is the most efficient:

path="/my/dir/structure/*"
backupdir=$(find $path -type d -prune | tail -n 1)

Explanation why this is a little better:

We do not need sub-shells (aside from the one for getting the result into the bash variable). We do not need a useless -exec ls -d at the end of the find command, it already prints the directory listing. We can easily alter this, e.g. to exclude certain patterns. For example, if you want the second newest directory, because backup files are first written to a tmp dir in the same path:

backupdir=$(find $path -type -d -prune -not -name "*temp_dir" | tail -n 1)

Tags:

Bash