Use bash to overwrite old file with a new file named according to current date

I am a complete beginner with linux, and need help making a bash script to create a file with a specific date in the file name.

I have a directory called /backups/, in which I would like to create a file according to the current date and time with some prefix text, such as /backups/backup_2023_09_15_14_00_00.txt. This part is already answered here).

The catch is that I want to remove the previous backup file if one already exists (which would be named according to the format backup_****_**_**_**_**_**.txt), and if the new file creation was successful.

Is there a way to do something like this?

Asked By: teeeeee

||

The following bash script fragment would use the list of positional parameters (see further down for a variant that uses a named array instead) to store all the pathnames of old backups. When the new backup has been created, here simulated using touch, the remembered old backups are deleted.

# Set backup dir variable and name of the new backup file.
backup_dir=/backups
printf -v backup_name 'backup_%(%Y_%m_%d_%H_%M_%S)T.txt' -1

# Remember any old backups.
shopt -s nullglob  # expand globs to nothing if no match
set -- "$backup_dir"/backup_????_??_??_??_??_??.txt

# Debugging output.
if [ "$#" -gt 0 ]; then
    printf 'Old file: %sn' "$@"
else
    echo 'No old files'
fi

# Create the new backup at "$backup_dir/$backup_name".
# Terminate if not successful.
touch "$backup_dir/$backup_name" || exit

# Remove old files if there were any.
rm -f "$@"

Using a named array to hold the old backup files rather than the list of positional parameters. The code is identical, except for the assignment to oldfiles and the expansions used with rm and for producing the debugging output.

# Set backup dir variable and name of the new backup file.
backup_dir=/backups
printf -v backup_name 'backup_%(%Y_%m_%d_%H_%M_%S)T.txt' -1

# Remember any old backups.
shopt -s nullglob  # expand globs to nothing if no match
oldfiles=( "$backup_dir"/backup_????_??_??_??_??_??.txt )

# Debugging output.
if [ "${#oldfiles[@]}" -gt 0 ]; then
    printf 'Old file: %sn' "${oldfiles[@]}"
else
    echo 'No old files'
fi

# Create the new backup at "$backup_dir/$backup_name".
# Terminate if not successful.
touch "$backup_dir/$backup_name" || exit

# Remove old files if there were any.
rm -f "${oldfiles[@]}"

Instead of terminating the script if the new backup isn’t created successfully, we could instead do the removal of the old files in an if statement, for example,

# Create the new backup.
# Remove old files if successful.
if touch "$backup_dir/$backup_file"
then
    rm -f "$@"    # or "${oldfiles[@]}" if you used the array and like typing longer things
fi
Answered By: Kusalananda

If you only want a single backup file then its easy – pseudo code looks like this:

Capture list of existing backup files
create new backup file
if new filecreated OK, delete files in list 

If create new backup file is simply a matter of copying a single small file, then this is probably overkill – its unlikely to fail. In such a case, just delete the existing files before creating the new one. But creating a large tar/cpio archive or offloading to back server is something else.

But that’s a bit boring. What about maintaining multiple backup files? If you know they will be created on a regular basis then you could do this:

find $BACKUPDIR -maxdepth 1 -mtime +7 -exec rm -f {} ;

which would keep the files created (or modified) in the last 7 days.

Or if you wanted to keep a number of versions (12 in below)….

ls -1 $BACKUPDIR/backup | sort | awk -v KEEP=12 '(NR>KEEP) { print $1 }' | xargs rm -f
Answered By: symcbean

You can do like this:

# Save the list of files in the backup folder
files=$(ls /backups/backup_[0-9][0-9][0-9][0-9]_[0-9][0-9]_[0-9][0-9]_[0-9][0-9]_[0-9][0-9]_[0-9][0-9].txt)

# [Do your backup here, exit if it fails]

# Delete the files previously in the backup folder
for file in $files
do
    rm -f "${file}"
done
Answered By: setenforce 1
Categories: Answers Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.