3

I wrote a find command, which finds the files, but excludes other files/directories. I did echo this code and copied it. If I paste it in the terminal, it works. Some files were excluded. But if I execute it from the script, it does not work as expected.

I tried to escape my variables, quote them, between brackets like $() or ${} but nothing worked.

My find code looks like this:

find ${StartDirs[*]} $pat -print

In fact it will be executed like:

find ./bin  -wholename './bin/backup2' -prune -o -wholename './bin/backup3' -prune -o -print

The second code above works in the terminal but not in the script. What did I do wrong?

For more info I will try to paste necessary code below I am trying to make a backup and want to do that with find and cp. Most code of my script are omitted. I think the code below is the necessary minimal code for this problem.

StartDirs=();
ExcludedFiles=(); #files/directories which needs to be excluded

#check and store excluded files
CheckExcludedFile(){ #this function will be called over and over again by another function (getopts). It depends on the chain of -x options. With the -x option I can decide which file i want to exclude. The Getopts function is also omitted.

    exclFile=`find $1 2>/dev/null | wc -l` 
    if [ $exclFile -lt 1 ]; then
        echo $FILEMAPNOTEXIST | sed 's~-~'$1'~g' # FILEMAPNOTEXIST is a variable from another script with error messages
        exit 0
    else
        ExcludedFiles+=($1) #add excluded file/dir path to array
    fi
}

MakeBackup(){
        for i in ${ExcludedFiles[*]}
        do
            s=" -wholename $i -prune -o"
            pat=$pat$s
        done
        # the code above edits the array elements of the EcludedFIles[]
        #For example by calling the script with the -x option (-x fileA -x fileB -x fileC) wordt als volgt: -wholename 'fileA' -prune -o -wholename 'fileB' -prune -o -wholename 'fileC' -prune -o.
        #the pat variable will be used for the find command to ignore files/directories

    mkdir -p ~/var

    echo "Start-time $(date '+%F %T')" >> ~/var/dq.log  

    find ./bin  -wholename './bin/backup2' -prune -o -wholename './bin/backup3' -prune -o -print
    #the code above should work like in terminal. That is not the case..

    # find ${StartDirs[*]} $pat -print #this should work also.

    # cp -av ${StartDirs[@]} $Destination >> ~/var/dq.log find command not working therefore this rule is commented

    echo "end-time $(date '+%F %T')" >> ~/var/dq.log
}

The expected result should simply be some files/directories being excluded if given.

If a full script is necessary, let me know.

Asger
  • 3,822
  • 3
  • 12
  • 37
FFBbodie
  • 111
  • 2
  • 12
  • Show your script. Which user runs your script? – Cyrus Jun 15 '19 at 12:27
  • 1
    Add output of `declare -p StartDirs` to your question. – Cyrus Jun 15 '19 at 12:28
  • Any chance you could provide a complete but minimal script to reproduce your problem, that we could run on our side? – joanis Jun 15 '19 at 12:46
  • I added some minimal code of which i think is necessary for this problem. If a complete script is necessary, please let me know – FFBbodie Jun 15 '19 at 13:28
  • You have a few functions here, but where are they called...?? –  Jun 15 '19 at 13:29
  • Btw., I'd put any reference to e.g. $1 and $i on the right hand side of an equal sign (=) in double quotes. –  Jun 15 '19 at 13:31
  • You need to call CheckExcludedFile or MakeBackup somewhere. –  Jun 15 '19 at 13:33
  • Thanks for trying to give us a minimal example; but as it is the find result is not used to backup anything but just prints its found files, and does not seem to depend on any of the fluff around it. What is it you expect here, and what is it about the find that does not work? – Peter - Reinstate Monica Jun 15 '19 at 13:40
  • I haven't come that far. I wanted to solve the find problem first and then use -exec with cp. The function are called from somewhere but i omitted those functions. Because they are not really important I think. – FFBbodie Jun 15 '19 at 14:36
  • Drop **everyting** in your script except the `find` call. Does it work? If yes, then **something else** in your original script prevents the `find` call to work. It could be `cd` call, which changed current directory, so relative path `./bin` becomes wrong. That is why we need [mcve] for being able to help you. – Tsyvarev Jun 16 '19 at 07:21
  • You are right, creating an minimal example would make it much easier for others to understand the issue. Fortunately, I have already fixed the issue :) – FFBbodie Jun 16 '19 at 12:15

1 Answers1

3

The command find ./bin -wholename './bin/backup2' -prune -o -wholename './bin/backup3' -prune -o -print should work as intended, provided the current directory is directly above bin/. This may be the cause of your problems: If in the real script you assemble path names which do not match the prefixes in the found paths then e.g. the prune will not work. Example: You have a dir /home/me; in it is bin/backup2/, bin/backup3/ and stuff-to-backup/. Now if you are in /home/me and execute find . it finds e.g. ./bin/backup2 which will be pruned.

But if you put this in a script and call the script with path arguments, e.g. /home/me, it will find the same files but the paths will be different, e.g. /home/me/bin/backup2, and will not prune it because it does not match the supplied exclude pattern, even though they are the same files. Likewise no patterns supplied with -wholename will be found. Here is a question which addresses this problem.

Peter - Reinstate Monica
  • 15,048
  • 4
  • 37
  • 62
  • Thank you, I added '.*' before the path. Example: `find ./bin -wholename '.*/bin/backup2' -prune -o -wholename '.*/bin/backup3' -prune -o -print` I stil don't completely understand this since my script is in the same path as the terminal where I executed my code. What is exactly the difference, I only adden .*? – FFBbodie Jun 15 '19 at 14:57
  • @FFBbodie The location of the script is irrelevant. Relative paths like `./bin` are resolved based on the working directory, which is inherited from the shell running the script. If you want the script to search relative to the script, see [BashFAQ @28](https://mywiki.wooledge.org/BashFAQ/028). – Gordon Davisson Jun 15 '19 at 18:46
  • I see now that it only works if the code is raw (`find ./bin -wholename '.*/bin/backup2' -prune -o -wholename '.*/bin/backup3' -prune -o -print`). it does not work with variable: find `${StartDirs[*]} $pat -print`. Why not? – FFBbodie Jun 15 '19 at 21:30
  • 1
    @FFBbodie The way you're storing command parameters in the `$pat` variable is doomed to fail for anything nontrivial; see [BashFAQ #50: I'm trying to put a command in a variable, but the complex cases always fail!](https://mywiki.wooledge.org/BashFAQ/050) You might be able to redo things using arrays (and the proper idiom to expand them -- always use double-quotes and `[@]` instead of `[*]`), but it looks like with the way you're passing things around, it's going to be quite a mess. – Gordon Davisson Jun 16 '19 at 01:39