Linux – bash – excluding directory in “for file in $(find …)”

backupbashfindfor-looplinux

I have to do a script, which copy all the *.txt files from home directory to the newly created directory specified in the first argument of this script (${1}).

If the backup directory already exists, I want to skip it. I was trying the -prune excluding in find, but it doesn't work for me. Finally I have made if statement in the loop, which also doesn't work, and I don't know why…Thank's for help!!

Here's my code:

#!/bin/bash

mkdir ${1}

for file in $(find ~/ -name *.txt)

do

    if [ ! -f ~/${1}/$file ]
    then
        cp -i -v $file -t ~/${1}
    fi

done

Best Answer

This should do:

#!/bin/bash

[[ -n "$1" ]] || { echo >&2 'Give me an argument!'; exit 1; }

destdir=$(readlink -m -- "$1")

[[ "$destdir" == *\** ]] && { echo >&2 "Sorry, I'm in the stupid situation where the destination dir contains the \`*' character. I can't handle this."; exit 1; }

mkdir -pv -- "$destdir" || { echo >&2 "Couldn't create directory \`$destdir'. Sorry."; exit 1; }

find "$HOME" -path "$destdir" -prune -o \( -name '*.txt' -exec cp -iv -t "$destdir" -- {} \; \)

Pro: Works with files that have spaces or funny symbols in their name (unlike yours) (except one stupid case, see Con below).

Con: As ormaaj pointed out in a comment, this might fail miserably if the name of your destination path contains the pattern character *. This case is safely taken into account, and the script exits gracefully if it ever happens.

Explanations.

  • Give an argument to that script. It can be absolute of relative to the current directory. readlink, with the -m option will take care to translate this to an absolute path: that's the variable destdir.
  • The directory $destdir is created with its parents, if applicable.
  • In home directory, if we find $destdir directory, we prune this branch, otherwise, we look for all *.txt files and copy them to $destdir.

Once again, this script is 100% safe regarding file names with funny symbols: spaces, newline characters or hyphens, except for the pattern character * in the destination directory name, but that case is handled safely by a graceful exit, instead of potentially screwing up the files.