1
\$\begingroup\$

This is my algorithm to backup data on Windows using Bash scripting language. I'm looking forward to any innovations, and better solutions. My task was to create a simple backup algorithm using dry-run and delete. Are there any simpler solutions? Also, adding a GUI would be a pretty nice training for me, but in my case, I'm not too familiar with that.

#!/bin/bash

src=$1
dst=$2

option1=$3
option2=$4

src_files=$(ls $src)
dst_files=$(ls $dst)

files_to_copy () {
    files_to_copy=()
    for file in $src_files; do
        if [[ ! $dst_files =~ $file ]]; then
            files_to_copy+=($file)
        fi
    done
    echo ${files_to_copy[@]}
}

files_to_delete () {
    to_delete=(  )
    for file in $dst_files; do
        if [[ ! $src_files =~ $file ]]; then
            to_delete+=($file)
        fi
    done
    echo ${to_delete[@]}
}

to_copy=$(files_to_copy)

if [[ "$option1" == "del" || "$option2" == "del" ]]; then
    to_delete=$(files_to_delete)
fi

dry_run () {
    for file in ${to_copy[@]}
    do
        echo cp $src/$file $dst
    done
    
    for file in ${to_delete[@]}
    do
        echo rm $dst/$file 
    done
}

run () {
    for file in ${to_copy[@]}
    do
        cp $src/$file $dst
    done
    
    for file in ${to_delete[@]}
    do
        rm $dst/$file 
    done
}

if [[ "$option1" == "dryrun" || "$option2" == "run" ]]; then
    dry_run
else
    run
fi

Thank you in advance, and have a nice day.

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

Since you're using Bash, then you can take advantage of array variables for src_files and dst_files. Definitely don't just expand $(ls) like that, because the result will be word-split according to $IFS.

Having built a neat array in files_to_copy(), we then lose all its structure by printing out and storing in a string variable.

I don't think $file is set when files_to_copy() is invoked - add set -u to make sure we don't attempt to use non-existent variables.

Instead of separate run and dry_run, we can use a variable to selectively enable 'echo' like this:

run()
{
    ${prefix+"${prefix[@]}"} cp "${to_copy[@]/#/$src/}" "$dst"
    ${prefix+"${prefix[@]}"} rm "${to_delete[@]/#/$dst/}"
}

dry_run()
{
    prefix=(echo) do_it "$@"
}

(I also simplified your loops into single commands, by substituting the directory at start of each filename, which works only if to_copy and to_delete are actually arrays of filenames).

\$\endgroup\$
2
  • \$\begingroup\$ Hii, when i was trying to use your run() function i'm getting errors "cp: cannot stat '/backupv1.sh understanding_swap.sh whiptail.sh': No such file or directory rm: cannot remove 'backup/': Is a directory" \$\endgroup\$ Commented Nov 16, 2022 at 15:28
  • \$\begingroup\$ Yes. As I said that will only work once to_copy and to_delete are correctly populated as arrays of filenames. I perhaps should have made that condition more prominent! \$\endgroup\$ Commented Nov 16, 2022 at 17:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.