Reputation: 1043
I have a folder with backups from a MySQL database that are created automatically. Their name consists of the date the backup was made, like so:
2010-06-12_19-45-05.mysql.gz
2010-06-14_19-45-05.mysql.gz
2010-06-18_19-45-05.mysql.gz
2010-07-01_19-45-05.mysql.gz
What is a way to get the filename of the last file in the list, i.e. of the one which in alphabetical order comes last?
In a shell script, I would like to do something like
LAST_BACKUP_FILE= ???
gunzip $LAST_BACKUP_FILE;
Upvotes: 21
Views: 15164
Reputation: 617
ls
can yield unexpected results when parsed by other commands if the filenames have unusual characters. The following always works:
for LAST_BACKUP_FILE in *; do : ; done
for LAST_BACKUP_FILE in *
loops through every filename (and folder name, if there are any) in order in the current directory, storing each in $LAST_BACKUP_FILE
do :
does nothing
done
finishes after the last file
Now, the last file is stored in $LAST_BACKUP_FILE
.
If you happen to want the first file, use this:
for FIRST_BACKUP_FILE in *; do break; done
The break
statement jumps out of the loop after the first file is stored in $FIRST_BACKUPT_FILE
.
(from comment below) If you want hidden files included in the search, then use the command shopt -s dotglob
before running the loops.
Upvotes: 8
Reputation: 72687
The shell is more powerful than many think. Just let it work for you. Assuming filenames without spaces,
set -- $(ls -r *.gz)
LAST_BACKUP_FILE=$1
does the trick with a single fork, no pipes, and you can even avoid the fork if your shell supports arithmetic expansion as in
set -- *.gz
shift $(($# - 1))
LAST_BACKUP_FILE=$1
Upvotes: 2
Reputation: 19247
@Sjoerd's answer is correct, I'll just pick a few nits from it:
you don't need the -1
option to enforce one path per line if you pipe the output somewhere:
ls | tail -n 1
you can use -r
to get the listing in reverse order, and take the first one:
ls -r | head -n 1
gunzip some.log.gz
will write uncompressed data into some.log
and remove some.log.gz
, which may or may not be what you want (probably isn't). if you want to keep the compressed source, pipe it into gunzip
:
gunzip < some.file.gz
you might want to protect the script against situation when the dir contains no files, since
gunzip $empty_variable
expands to just
gunzip
and such invocation will wait indefinitely for data on standard input:
latest="$(ls -r /some/where/*.gz | head -1)"
if test -z "$latest"; then
# there's no logs yet, bail out
exit
fi
gunzip < $latest
Upvotes: 11
Reputation: 75619
ls -1 | tail -n 1
If you want to assign this to a variable, use $(...)
or backticks.
FILE=`ls -1 | tail -n 1`
FILE=$(ls -1 | tail -n 1)
Upvotes: 24