0

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?

4

3 Answers 3

0

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: %s\n' "$@"
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: %s\n' "${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
4
  • Thanks for your answer. I think I have almost followed it properly. Two things: 1) in the second version, with the named array, does the "rm" command at the end somehow cycle through all items in the array? 2) Could you add some code after the creation of the "oldfiles" variable, which echoes each file name to the terminal output (just so I can check it picks them all up correctly for debugging)?
    – teeeeee
    Commented Sep 15, 2023 at 14:23
  • @teeeeee The expansion "${oldfiles[@]}" expands to the list of names that the pattern matched. I will add an output statement.
    – Kusalananda
    Commented Sep 15, 2023 at 14:24
  • 1
    @teeeeee Yes, you failed to copy the shopt line.
    – Kusalananda
    Commented Sep 15, 2023 at 14:41
  • Awesome, it works beautifully! Thanks so much for your time.
    – teeeeee
    Commented Sep 15, 2023 at 15:27
-1

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
6
  • In your step 1), how do you capture the list of existing backup files? Remember, backup files are only those in the format "backup_****_**.ext". I don't want to delete everything in the directory - only those which are backup files, based on the criterion above.
    – teeeeee
    Commented Sep 15, 2023 at 14:01
  • FILES2DEL="$( ls -1 $BACKUPDIR/backup_????_??_??_??_??_??.txt)" (i.e. same as @Kusalananda)
    – symcbean
    Commented Sep 15, 2023 at 14:05
  • 1
    This answer says it's bad to parse the output of "ls" for getting the list? unix.stackexchange.com/a/191650/413987
    – teeeeee
    Commented Sep 15, 2023 at 14:07
  • Read it again - it causes problems if the filenames contain spaces. You already told us they did not.
    – symcbean
    Commented Sep 15, 2023 at 14:08
  • Yep, you're right :)
    – teeeeee
    Commented Sep 15, 2023 at 14:10
-2

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
3
  • This deletes everything in the backups directory. I want to delete only ones which match a particular format (backup_****_**.ext).
    – teeeeee
    Commented Sep 15, 2023 at 14:04
  • Yes sorry, I meant "deletes everything in the backups directory, except for the newly created backup".
    – teeeeee
    Commented Sep 15, 2023 at 14:12
  • I fixed the ls command so it does what you want. Commented Sep 15, 2023 at 14:30

You must log in to answer this question.

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