0

I wrote a bash script to run on macOS 10.l0.5. I hoped to simplify the script. In the example script below, the first invocation of the find command gives the desired output. In the original script, I have a multiple find commands with the same set of directories excluded. I hoped to place them in a variable. The second find command show my failed attempt.

I do not know why this failed.

Any way of sharing common options between multiple find commands is acceptable to me. No, I do not want to exclude all hidden directories.

I run this with an external flash drive. This script is all read only.

#! /bin/bash

sourceDir="/Volumes/DOSDISK"

echo "--------------- find works as expected ------------------------------"
find ${sourceDir} \
 ! -path "${sourceDir}/.Trashes" \
 ! -path "${sourceDir}/.Trashes/*" \
 ! -path "${sourceDir}/.Spotlight-V100" \
 ! -path "${sourceDir}/.Spotlight-V100/*" \
 ! -path "${sourceDir}/.fseventsd" \
 ! -path "${sourceDir}/.fseventsd/*" \
 -type d \
 -exec echo {} \;


echo "----------------------------- does not skip hidden directories -----------"
dirsToSkip=" ! -path \"${sourceDir}\" "
echo "dirsToSkip is -1->${dirsToSkip}"
dirsToSkip="${dirsToSkip}! -path \"${sourceDir}/.Trashes\" "
echo "dirsToSkip is -2->${dirsToSkip}"
dirsToSkip="${dirsToSkip}! -path \"${sourceDir}/.Trashes/*\" " 
echo "dirsToSkip is -3->${dirsToSkip}"
dirsToSkip="${dirsToSkip}! -path \"${sourceDir}/.Spotlight-V100\" " 
echo "dirsToSkip is -4->${dirsToSkip}"
dirsToSkip="${dirsToSkip}! -path \"${sourceDir}/.Spotlight-V100/*\" " 
echo "dirsToSkip is -5->${dirsToSkip}"
dirsToSkip="${dirsToSkip}! -path \"${sourceDir}/.fseventsd\" " 
echo "dirsToSkip is -6->${dirsToSkip}"
dirsToSkip="${dirsToSkip}! -path \"${sourceDir}/.fseventsdf/*\" " 
echo "dirsToSkip is -7->${dirsToSkip}"

echo "see in print ---> "find ${sourceDir} \
 ${dirsToSkip} \
 -type d \
 -exec echo {} \;
echo -e "\n The non-working thing. "
find ${sourceDir} \
 ${dirsToSkip} \
 -type d \
 -exec echo {} \;

the output. When adding debug to the script #! /bin/bash -v -x, I notice the ! printed as '!'.

mac $  ./config/trybash.bash
--------------- find works as expected ------------------------------
/Volumes/DOSDISK
/Volumes/DOSDISK/level2
/Volumes/DOSDISK/level3
----------------------------- does not skip hidden directories -----------
dirsToSkip is -1-> ! -path "/Volumes/DOSDISK" 
dirsToSkip is -2-> ! -path "/Volumes/DOSDISK" ! -path "/Volumes/DOSDISK/.Trashes" 
dirsToSkip is -3-> ! -path "/Volumes/DOSDISK" ! -path "/Volumes/DOSDISK/.Trashes" ! -path "/Volumes/DOSDISK/.Trashes/*" 
dirsToSkip is -4-> ! -path "/Volumes/DOSDISK" ! -path "/Volumes/DOSDISK/.Trashes" ! -path "/Volumes/DOSDISK/.Trashes/*" ! -path "/Volumes/DOSDISK/.Spotlight-V100" 
dirsToSkip is -5-> ! -path "/Volumes/DOSDISK" ! -path "/Volumes/DOSDISK/.Trashes" ! -path "/Volumes/DOSDISK/.Trashes/*" ! -path "/Volumes/DOSDISK/.Spotlight-V100" ! -path "/Volumes/DOSDISK/.Spotlight-V100/*" 
dirsToSkip is -6-> ! -path "/Volumes/DOSDISK" ! -path "/Volumes/DOSDISK/.Trashes" ! -path "/Volumes/DOSDISK/.Trashes/*" ! -path "/Volumes/DOSDISK/.Spotlight-V100" ! -path "/Volumes/DOSDISK/.Spotlight-V100/*" ! -path "/Volumes/DOSDISK/.fseventsd" 
dirsToSkip is -7-> ! -path "/Volumes/DOSDISK" ! -path "/Volumes/DOSDISK/.Trashes" ! -path "/Volumes/DOSDISK/.Trashes/*" ! -path "/Volumes/DOSDISK/.Spotlight-V100" ! -path "/Volumes/DOSDISK/.Spotlight-V100/*" ! -path "/Volumes/DOSDISK/.fseventsd" ! -path "/Volumes/DOSDISK/.fseventsdf/*" 
see in print ---> find /Volumes/DOSDISK ! -path "/Volumes/DOSDISK" ! -path "/Volumes/DOSDISK/.Trashes" ! -path "/Volumes/DOSDISK/.Trashes/*" ! -path "/Volumes/DOSDISK/.Spotlight-V100" ! -path "/Volumes/DOSDISK/.Spotlight-V100/*" ! -path "/Volumes/DOSDISK/.fseventsd" ! -path "/Volumes/DOSDISK/.fseventsdf/*" -type d -exec echo {} ;

 The non-working thing. 
/Volumes/DOSDISK
/Volumes/DOSDISK/.Trashes
/Volumes/DOSDISK/.Trashes/501
/Volumes/DOSDISK/.Trashes/501/.Spotlight-V100
/Volumes/DOSDISK/.Trashes/501/.Spotlight-V100/Store-V2
/Volumes/DOSDISK/.Trashes/501/.Spotlight-V100/Store-V2/FF996064-BEDD-474E-9E76-7F8ABD688B09
/Volumes/DOSDISK/.Spotlight-V100
/Volumes/DOSDISK/.Spotlight-V100/Store-V2
/Volumes/DOSDISK/.Spotlight-V100/Store-V1
/Volumes/DOSDISK/.fseventsd
/Volumes/DOSDISK/level2
/Volumes/DOSDISK/level3
mac $ 
historystamp
  • 1,418
  • 4
  • 14
  • 24
  • 1
    Your embedded quotes are taken literally. – melpomene Jul 07 '19 at 21:28
  • 1
    Storing quotes (or other shell syntax) in variables doesn't work; use an array instead. See [Why does shell ignore quotes in arguments passed to it through variables?](https://stackoverflow.com/questions/12136948/why-does-shell-ignore-quotes-in-arguments-passed-to-it-through-variables) and [BashFAQ #50: I'm trying to put a command in a variable, but the complex cases always fail!](http://mywiki.wooledge.org/BashFAQ/050) – Gordon Davisson Jul 07 '19 at 21:55
  • Oh, I see now. The text from ${dirsToSkip} wasn't tokenized. Instead it was passed as a long string. – historystamp Jul 08 '19 at 00:26
  • 1
    @historystamp "tokenized" is the wrong word; it wasn't *parsed*. Or rather, it was sort of weirdly half-parsed. Specifically, it was split into "words" based on whitespace (which is sort of tokenization), and then any words with wildcards were expanded into lists of matching filenames. But quotes and escapes were not parsed -- that's done at an earlier stage of the process, before variables are expanded. – Gordon Davisson Jul 08 '19 at 01:30

1 Answers1

0

With the advice gotten in this thread, I developed this script. To run, you need to change the variable sourceDir to a path of one of your directories. This is a print to console only script.

#! /bin/bash
#
# Answer to my question:
#   https://stackoverflow.com/questions/56926105/combining-unix-find-command-options?noredirect=1#comment100396210_56926105
#  see Gordon Davisson's comment
#
sourceDir="/Volumes/DOSDISK"

echo "--------------- find works as expected ------------------------------"
find ${sourceDir} \
 ! -path "${sourceDir}" \
 ! -path "${sourceDir}/.Trashes" \
 ! -path "${sourceDir}/.Trashes/*" \
 ! -path "${sourceDir}/.Spotlight-V100" \
 ! -path "${sourceDir}/.Spotlight-V100/*" \
 ! -path "${sourceDir}/.fseventsd" \
 ! -path "${sourceDir}/.fseventsd/*" \
 -type d \
 -exec echo {} \;


echo "----------------------------- Another way to skip hidden directories -----------"
# You place one and only one argument in each array element.
# avoid add extraneous leading and trailing blanks.
# No need to double quote strings.
#

fileargs=()

fileargs+=("!")
fileargs+=("-path") 
fileargs+=("${sourceDir}/.Trashes")

fileargs+=("!")
fileargs+=("-path") 
fileargs+=("${sourceDir}/.Trashes/*")

fileargs+=("!")
fileargs+=("-path") 
fileargs+=("${sourceDir}/.Spotlight-V100")

fileargs+=("!")
fileargs+=("-path") 
fileargs+=("${sourceDir}/.Spotlight-V100/*")

fileargs+=("!")
fileargs+=("-path") 
fileargs+=("${sourceDir}/.fseventsd")

fileargs+=("!")
fileargs+=("-path") 
fileargs+=("${sourceDir}/.fseventsdf/*" )

echo "fileargs are -->${fileargs[@]}<--"

# This invocation is optional.  Remove comments to see 
# the arguments printed out
# you will need the associated bash file.
#echo -e "\n Print args. "
#/Users/mac/config/displayinput.bash ${sourceDir} \
#  ! -path "${sourceDir}" \
# "${fileargs[@]}" \
# -type d \
# -exec echo {} \;

echo -e "\n A second working thing. \n"
find ${sourceDir} \
  ! -path "${sourceDir}" \
 "${fileargs[@]}" \
 -type d \
 -exec echo {} \;

exit 0

Here is the optional displayinput.bash script

#! /bin/bash

# display input
echo -e "\nin displayinput.bash"
echo -e "\nall args -->${*}<--\n"

declare -i position
position="1";

while [[ $# -gt 0 ]]
do
  key="$1"
  echo "input #${position} token ${1}"
  shift # past argument
  position="position + 1";
done
historystamp
  • 1,418
  • 4
  • 14
  • 24