Bash - excluding the directory in "for a file in $ (find ...)"

I need to make a script that will copy all * .txt files from the 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 tried using -prune ex in search, but this does not work for me. Finally, I did if the statement is in a loop that also doesn't work, and I don't know why ... Thanks for the help!

Here is 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 
+4
source share
3 answers

You have an error in the code, you are creating a directory:

 mkdir ${1} 

But copying and testing the other way ( -f ~/${1}/$file , -t ~/${1} ). Create a variable to prevent such errors:

 #!/bin/bash dest=~/${1} [ -d "$dest" ] || mkdir "$dest" SAVEIFS=$IFS IFS=$(echo -en "\n\b") for file in $(find ~/ -name '*.txt' -print) do dfile="$dest/"$(basename "$file") if [ "$file" -ef "$dfile" ]; then echo same else cp -i -v "$file" -t "$dfile" fi done IFS=$SAVEIFS 
0
source

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 with spaces or funny characters in their name (unlike yours) (except for one stupid case, see below).

Con: As ormaaj noted in a comment, this may fail if the name of your destination path contains a wildcard character * . This case is safely taken into account, and the script exquisitely exits if it ever happens.

Explanations.

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

Once again, this script is 100% safe with respect to file names with funny characters: spaces, newlines or hyphens, with the exception of the wildcard character * in the name of the target directory, but this case is safely handled by an elegant output rather than potentially twisting files.

+1
source

You can simplify this for

 mkdir -p "$1" find ~/ -name "$1" -prune , -name '*.txt' -print0 | xargs -0 cp -n -v -t "$1" 

You must specify *.txt , otherwise the shell will expand it to all .txt files in the current directory, and not to search for all .txt files below your home directory. -name "$1" -prune excludes the backup directory.

xargs calls cp using a lot of file names, and it saves a lot of time.

cp -n instead of cp -i prevents overwriting files that already exist. If you want to keep it, you can replace -n with -i , of course.

If you want to maintain a directory hierarchy, rsync might be better suited for this backup task.

0
source

All Articles