• Uncategorized

About linux : Backup-the-first-argument-on-bash-script

Question Detail

I wrote a script to backup the first argument that the user input with the script:

#!/bin/bash
file=$1/$(date +"_%Y-%m-%d").tar.gz
if [ $1 -eq 0 ]
then
    echo "We need first argument to backup"
else
    if [ ! -e "$file" ]; then
        tar -zcvf $1/$(date +"_%Y-%m-%d").tar.gz $1
    else 
        exit 
    fi
fi 

The result that i want from the script is

  1. backup folder the first argument that user input
  2. save the backup file into folder that user input with date time format.

but the script is not running when I try to input the argument. What’s wrong with the script?

Question Answer

The backup part of your script seem to be working well, but not the part where you check that $1 is not empty.

Firstly you would need quotes around $1, to prevent that it expends to nothing. Without the quotes the shell sees it as

if [ -eq 0 ]

and throws an error.

Secondly it would be better to use the -z operator to test if the variable exists:

if [ -z "$1" ]

Now you script should work as expected

I see several problems:

  • As H. Gourlé pointed out, the test for whether an argument was passed is wrong. Use if [ -z "$1" ] to check for a missing/blank argument.
  • Also, it’s almost always a good idea to wrap variable references in double-quotes, as in "$1" above. You do this in the test for whether $file exists, but not in the tar command. There are places where it’s safe to leave the double-quotes off, but the rules are complicated; it’s easier to just always double-quote.
  • In addition to checking whether $1 was passed, I’d recommend checking whether it corresponds to a directory (or possibly file) that actually exists. Use something like:

    if [ -z "$1" ]; then
        echo "$0: We need first argument to backup" >&2
    elif [ ! -d "$1" ]; then
        echo "$0: backup source $1 not found or is not a directory" >&2
    

    BTW, note how the error messages start with $0 (the name the script was run as) and are directed to error output (the >&2 part)? These are both standard conventions for error messages.

  • This isn’t serious, but it really bugs me: you calculate $1/$(date +"_%Y-%m-%d").tar.gz, store it in the file variable, test to see whether something by that name exists, and then calculate it again when creating the backup file. There’s no reason to do that; just use the file variable again. The reason it bugs me is partly that it violates the DRY (“Don’t Repeat Yourself”) principle, partly that if you ever change the naming convention you have to change it consistently in two places or the script will not work, and partly because in principle it’s possible that the script will run just at midnight, and the first calculation will get one day and the second will get a different day.
  • Speaking of naming conventions, there’s a problem with how you store the backup file. If you put it in the directory that’s being backed up, then the first day you’ll get a .tar.gz file containing the previous contents of the directory. The second day you’ll get a file containing the regular contents plus the first backup file. Thus, the second day’s backup will be about twice as big. The third day’s backup will contain the regular contents, plus the first two backup files, so it’ll be four times as big. And the fourth day’s will be eight times as big, then 16 times, then 32 times, etc.

    You need to either store the backup file somewhere outside the directory being backed up, or add something like --exclude="*.tar.gz" to the arguments to tar. The disadvantage of the --exclude option is that it may exclude other .tar.gz files from the backup, so I’d really recommend the first option. And if you followed my advice about using "$file" everywhere instead of recalculating the name, you only need to make a change in one place to change where the backup goes.

One final note: run your scripts through shellcheck.net. It’ll point out a lot of common errors and bad practices before you discover them the hard way.

Here’s a corrected version of the script (storing the backup in the directory, and excluding .tar.gz files; again, I recommend the other option):

#!/bin/bash

file="$1/$(date +"_%Y-%m-%d").tar.gz"

if [ -z "$1" ]; then
    echo "$0: We need first argument to backup" >&2

elif [ ! -d "$1" ]; then
    echo "$0: backup source $1 not found or is not a directory" >&2

elif [ -e "$file" ]; then
    echo "$0: A backup already exists for today" >&2

else
    tar --exclude="*.tar.gz" -zcvf "$file" "$1"
fi

You may also like...

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.