Dan J
Dan J

Reputation: 53

Linux Bash - excluding directories with find

i'm having some trouble with a bash script i'm currently writing, and I've isolated the problematic code.

Find command when using argument from variable does not exclude directories.

Now i need to assign the '-not -path ./dir' argument to a variable as it's being looped over, however if i do, it doesn't seem to work.

I've included below the command that produces the desired output, along with my version which currently is broken. Please see my test below:

Variable assignment

findIgnorePaths="-not -path ./\.git\* -not -path ./administrator/cache\* -not -path ./images\* -not -path ./logs\* -not -path ./cache\* -not -path ./media\* -not -path ./plugins\* -not -path ./tmp\*"

Desired output.

find ./ -type d -not -path ./\.git\* -not -path ./administrator/cache\* -not -path ./images\* -not -path ./logs\* -not -path ./cache\* -not -path ./media\* -not -path ./plugins\* -not -path ./tmp\*

Broken output

find ./ -type d ${findIgnorePaths}

And for anyone who wants to see my script i'm working on which the problem above resides in, then please take a look below:

Original script (Not required to read to answer question, but... provided for those curious souls)

#!/bin/sh

declare -a ignoreDirs=()
findIgnorePaths=""
seperator="\e[33m**********************************\e[0m\n"

clear
printf "\n\n"

if [[ "${PWD##*/}" != "public_html" ]]
then
    printf "\e[31mThis script will not run unless current location is; /home/*/public_html/*\e[0m\n"
    exit
fi

echo "Site Locker! This will change all directory permissions to 555. And all file permissions to 444. Read only accces."

echo #Move to new line
echo "Are you sure you want to make changes to files/directories within the below location?"
printf "$seperator"
printf "\e[0;49;96m${PWD##/home/}\e[0m\n"
printf "$seperator"
echo #Move to new line

read -r -p "Y/n " response
echo #Move to new line
if [[ $response =~ ^([nN][oO]|[nN])$ ]]
then
    printf "\n\e[31mNo changes made. Quitting.\e[0m\n\n"
    exit
fi

printf "\e[95mIf you're working with a Joomla site, please select\nthe **JOOMLA** preset in the list below.\e[0m\n\nPlease select directory #) to add to the ignore list:\n\e[92m"

currentDir=( "**SAVE/SKIP**" "**JOOMLA**" )
currentDir+=( $(find . -maxdepth 1 -type d) )
select DIR in ${currentDir[@]};
do
  case $DIR in
        *SAVE*)
          printf "\n\n\e[92mDone!!\e[0m\n\n"
          break
          ;;
        *JOOMLA*)
          printf "\n\e[92mApplying Joomla preset.\n"
          ignoreDirs+=("./.git" "./administrator/cache" "./cache" "./images" "./logs" "./media" "./tmp" "./plugins")
          findIgnorePaths+=" -not -path ./\.git\* -not -path ./administrator/cache\* -not -path ./images\* -not -path ./logs\* -not -path ./cache\* -not -path ./media\* -not -path ./plugins\* -not -path ./tmp\*"
          printf "\n\n\e[31mIgnore list:\n"
          for item in "${ignoreDirs[@]}"
          do
              printf "$item\n"
          done
          ;;
        *)
          ignoreDirs+=("$DIR")
          findIgnorePaths+=" -not -path ${DIR}\*"
          printf "\n\n\e[31mIgnore list:\n"
          for item in "${ignoreDirs[@]}"
          do
              printf "$item\n"
          done
          printf "\e[92m"
          ;;
  esac
done
findIgnorePaths=$(echo ${findIgnorePaths} | cut -c 1-)

printf "\e[0m\n"

echo #Move to new line
printf "$seperator"
echo #Move to new line

echo "Apply 555 permissions to the below directories & all sub directories? "
printf "$seperator"
printf "\e[0;49;96m"

echo
echo "$findIgnorePaths"
echo
find ./ -maxdepth 1 -type d -not -path ./\.git\* -not -path ./administrator/cache\* -not -path ./images\* -not -path ./logs\* -not -path ./cache\* -not -path ./media\* -not -path ./plugins\* -not -path ./tmp\*
echo
find ./ -maxdepth 1 -type d ${findIgnorePaths}
echo



printf "\e[0m\n"
printf "$seperator"

read -r -p "Y/n " response
echo #Move to new line
if [[ $response =~ ^([yY][eE][sS]|[yY])$ ]]
then
    find ./ -type d $findIgnorePaths -exec chmod 555 {} +
    printf "\e[92mChanged directory permissions to 555\e[0m\n\n"
else
    printf "\e[31mSkipping this step. No directory permissions were set.\e[0m\n\n"
fi

read -r -p "Apply 444 permissions to all files in; ${PWD##*/}? Y/n " response
echo #Move to new line
if [[ $response =~ ^([yY][eE][sS]|[yY])$ ]]
then
    find ./ -type f $findIgnorePaths -exec chmod 444 {} +
    printf "\e[92mChanged file permissions to 444\e[0m\n\n"
else
    printf "\e[31mSkipping this step. No file permissions were set.\e[0m\n\n"
fi

printf "\n\e[92mFinished!\e[0m\n\n"

Upvotes: 4

Views: 309

Answers (1)

miken32
miken32

Reputation: 42744

This is Bash FAQ 50, which advises you to use an array variable to pass parameters to programs:

findIgnorePaths=(-not -path './.git*' -not -path './administrator/cache*' -not -path './images*' -not -path './logs*' -not -path './cache*' -not -path './media*' -not -path './plugins*' -not -path './tmp*')
find ./ -type d "${findIgnorePaths[@]}"

Note directory globs are single quoted so they aren't interpreted by the shell when the variable is created. Your backslash escapes were doing the same thing; it's a matter of personal preference which one you find easier to read.

Running scripts through shellcheck.net is always a good idea to find any problems that might be lurking.

Also, /bin/sh is not /bin/bash, so fix your shebang!

Upvotes: 3

Related Questions