6

Some time ago I wrote a script that moves files and directories from Downloads to .Downloads if they are older than 3 days, and delete them from this directory after 30 days. It is working just fine, but only for files with no spaces.

I investigated and found that the find command that I use in the script is not working as I expected for any file or directory with spaces in their name.

Here is what find does:

find command output

I expected to see the find command find the files with spaces too.

Here is the script:

#! /bin/bash
# set -x
export DISPLAY=:0.0

# true - delete, else - move
function process(){
    if [ "$2" = "DELETE" ]; then
        rm -r "$1" && notify-send "$3 $1 deleted!"
    else
    mv "$1" "../.Downloads/$1" && notify-send "$3 $1 moved to ~/.Downloads/$1!"
    fi
}

# remove empty directories
for emptyDir in `find ~/Desktop/ ~/Downloads/ -empty -type d`; do
    notify-send "Directoy $emptyDir was deleted, because was empty!"
done
find ~/Desktop/ ~/Downloads/ -empty -type d -delete

# remove / move old files / directorie
if [ -z "$1" ] || [ "${1,,}" != "delete" ] && [ "${1,,}" != "move" ]; then
    echo "Give as parameter mode ( delete / move )"
    exit
fi

if [ "${1,,}" == "delete" ]; then
    day=30
    path=".Downloads"
    mode="DELETE"
else
    day=2
    path="Downloads"
    mode="MOVE"
  cr  
  if [ ! -d "~/.Downloads" ]; then
    mkdir -p ~/.Downloads
  fi
fi

cd ~/$path

for element in *
do
    if [ -d "$element" ]; then
        if [ $(find "$element" -type f -mtime -$day | wc -l) -eq 0 ]; then
            process "$element" "$mode" "Directory"
        fi
    else
        if [ $(find `pwd` -name "$element" -mtime +$day | wc -l) -gt 0 ]; then
            process "$element" "$mode" "File"
        fi
    fi
done

I would kindly ask you to tell me what I may be doing wrong.

Thanks in advance!

1
  • 1
    You could put something as simple as @reboot [username] find ~/Downloads/ -mtime +3 -exec gio trash {} \; in your crontab. My distro is set to wipe trash files after 30 days, but that could also be done manually with the trash-cli package.
    – GammaGames
    Aug 26, 2021 at 14:30

1 Answer 1

13

tl;dr: it's not the spaces, it's the brackets1

The find command's -name test uses shell glob expressions - adding quotes around the argument prevents glob special characters from being interpreted by your shell, but find still requires them to be escaped.

Ex.

$ touch 'filename with [brackets] in it'
$ find . -name 'filename with [brackets] in it'
$

(no results - because [brackets] means any single character in the set b, r, a, c, k, e, t, s); whereas

$ find . -name 'filename with \[brackets\] in it'
./filename with [brackets] in it

If you need to implement this programatically, you could perhaps use the bash shell's printf to add the required escapes:

$ element='filename with [brackets] in it'
$ find . -name "$(printf '%q' "$element")"
./filename with [brackets] in it

  1. however you WILL have an issue with whitespace in the line

    for emptyDir in `find ~/Desktop/ ~/Downloads/ -empty -type d`; do
    

    See Why is looping over find's output bad practice?

  2. there are a number of other issues, for example the quoted ~ in [ ! -d "~/.Downloads" ] will not expand to $HOME - generally you should avoid ~ in scripts

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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