1

enter image description here

Given the above folder paths, I am trying to write a script that will delete files older than a certain amount of days. I am trying to use some more advanced techniques than just hard coding the paths (my real life examples has ALOT more folders). Here is what I have so far:

#!/bin/bash

FILEAGE=15

#Array of folders to clean
dir_array=(
"/srv/*/folderA"
"/srv/level1D/*/folderA"
)


#function to be used for deleting files.  Needs to be called with a path
function dir_delete() {
    echo "Deleting:"
    find $1 -type f -mindepth 1 -maxdepth 1 -mtime +$FILEAGE -delete -print
    echo ""
}

echo "##### Looping through dir_array array and using dir_delete function to delete files older than $FILEAGE days #####"
for d in "${dir_array[@]}";do
    if [ -d $d ];then

        echo "##### Deleting all files older than $FILEAGE in $d #####"
        dir_delete $d

    else
        echo "##### Did not find directory: \$d #####"
        echo ""
    fi

done

My script is returning that it can't find the directories like so:

Did not find directory: /srv/*/folderA

Note: There will be files throughout these folders under 15 days that can't be deleted.

Update

Using @Kusalananda suggestion '/srv/'*'/folderA' fixed it for me. I'm leaving the wrong code in my original post above should anyone want to see what I was doing wrong.

  • I don't think you can provide multiple root paths with e. g. find /path/*/to/places. The easiest option for me off the top of my head would be for rootpath in /srv/*/folderA; do find "$rootpath" [...]; done. – DopeGhoti Apr 12 at 18:26
  • * will not be expanded when it's quoted. Do you know that the mtime of a directory only updates when a file is deleted or created in it? – Kusalananda Apr 12 at 18:53
  • 1
    @DopeGhoti find does support multiple search paths, but the * is expanded in the wrong place. It should be expanded in the array, not in the execution of the find command. – Kusalananda Apr 12 at 18:54
1

The shell globbing pattern * is not expanded within double quotes. This means that your loop

for d in "${dir_array[@]}";do

is looping over patterns. In your call to dir_delete, you use the patterns unquoted, so they would be expand there (but it never gets there). The function would however only use the first word of whatever matches the pattern in the call to find.

The real show-stopper is that the patterns will also be expanded in the [ -d $d ] test, which is awkward since the -d test only ever takes a single pathname. This is, in the end, why the script fails.

Instead, make sure that the patterns are properly expanded when assigning to dir_array:

dir_array=(
    /srv/*/folderA
    /srv/level1D/*/folderA
)

If folderA or some other part of the pathnames contains spaces etc., that part of the pathname should be quoted, but the * should not be quoted.

Also remember to double quote the expansions of all variables, unless you know the contexts in which they don't need to be quoted.

There may be quoting issues with the following lines:

  • if [ -d $d ];then
  • find $1 -type f -mindepth 1 -maxdepth 1 -mtime +$FILEAGE -delete -print
  • dir_delete $d

Also consider using printf rather than echo when outputting variable data.

Related:

  • Your suggestion of using '/srv/'*'/folderA' worked for me. Thanks again. – JuanD Apr 12 at 20:42
1

You can do this with the extended glob option which will allow you to expand wildcards within a variable with *()

shopt -s extglob
dir_array=(
    "/srv/*(*)/folderA"
    "/srv/level1D/*(*)/folderA"
)

The expansion would happen at the for d in ... which I think is the correct point.

  • 1
    No, just use /srv/*/folderA unquoted (or '/srv/'*'/folderA'). It will expand correctly at the time of assigning to dir_array. – Kusalananda Apr 12 at 20:21
  • @XrXca your suggestion gave me the following message: [: /srv/level1A/folderA: binary operator expected – JuanD Apr 12 at 20:30
  • @Kusalananda I think your solution is working. Testing a few more scenarios now. Thank you much. I dont know if I can accept a sub comment as an answer. – JuanD Apr 12 at 20:31
  • @Kusalananda: Either should work, I tend to use the () construct when I'm using extglobs just because it's obvious it's not "normal", when a block of code is copied from one script to another, and I use the @(A|B|C).construct quite a bit.so it's "similar' in my mind. – XrXca Apr 12 at 21:02
  • @XrXca I'm just looking at the code and noticing that the only thing the script is using bash for (and not /bin/sh) is that single array. Changing it to set -- patterns would allow it to run under /bin/sh (the loop would loop over "$@" instead). My personal preference is to use /bin/sh, which is why I commented the way I did. Apart from that, you may well be right. – Kusalananda Apr 12 at 21:06

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.