简体   繁体   中英

Get the newest directory to a variable in Bash

I would like to find the newest sub directory in a directory and save the result to variable in bash.

Something like this:

ls -t /backups | head -1 > $BACKUPDIR

Can anyone help?

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

$(...)在子shell 中评估语句并返回输出。

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 .

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.

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, eg 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)

With GNU find you can get list of directories with modification timestamps, sort that list and output the newest:

find . -mindepth 1 -maxdepth 1 -type d -printf "%T@\t%p\0" | sort -z -n | cut -z -f2- | tail -z -n1

or newline separated

find . -mindepth 1 -maxdepth 1 -type d -printf "%T@\t%p\n" | sort -n | cut -f2- | tail -n1

With POSIX find (that does not have -printf ) you may, if you have it, run stat to get file modification timestamp:

find . -mindepth 1 -maxdepth 1 -type d -exec stat -c '%Y %n' {} \; | sort -n | cut -d' ' -f2- | tail -n1

Without stat a pure shell solution may be used by replacing [[ bash extension with [ as in this answer .

The above solution doesn't take into account things like files being written and removed from the directory resulting in the upper directory being returned instead of the newest subdirectory.

The other issue is that this solution assumes that the directory only contains other directories and not files being written.

Let's say I create a file called "test.txt" and then run this command again:

echo "test" > test.txt
ls -t /backups | head -1
test.txt

The result is test.txt showing up instead of the last modified directory.

The proposed solution "works" but only in the best case scenario.

Assuming you have a maximum of 1 directory depth, a better solution is to use:

find /backups/* -type d -prune -exec ls -d {} \; |tail -1

Just swap the "/backups/" portion for your actual path.

If you want to avoid showing an absolute path in a bash script, you could always use something like this:

LOCALPATH=/backups
DIRECTORY=$(cd $LOCALPATH; find * -type d -prune -exec ls -d {} \; |tail -1)

I would like to find the newest sub directory in a directory and save the result to variable in bash.

Something like this:

ls -t /backups | head -1 > $BACKUPDIR

Can anyone help?

Your "something like this" was almost a hit:

BACKUPDIR=$(ls -t ./backups | head -1)

Combining what you wrote with what I have learned solved my problem too. Thank you for rising this question.

Note: I run the line above from GitBash within Windows environment in file called ./something.bash .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM