This one is stumping me quite well! Big points for a resolution!
I need to traverse a directory and all levels below it to discover any files or directories that do not match a pattern.
I'm using find command -
find -L /home/user/inbox \( ! -path /home/user/inbox -a ! -path '/home/user/inbox/*' -a ! -path /home/user/inbox/imaging -a ! -path '/home/user/inbox/imaging/*' \) -ls
The error -
find -L /home/user/inbox \( ! -path /home/user/inbox -a ! -path '/home/user/inbox/*' -a ! -path /home/user/inbox/imaging -a ! -path '/home/user/inbox/imaging/*' \) -ls: No such file or directory
Yes, each of those directories in the find command do indeed exist -
ls -ld /home/user/inbox /home/user/inbox/imaging/
drwxr-xr-x. 5 user grp-ftp-admin 8192 Jan 13 12:45 /home/user/inbox
drwxr-xr-x. 3 user grp-ftp-admin 152 Jan 13 12:21 /home/user/inbox/imaging/
The entire script source -
#!/usr/bin/env bash
function findInvalidArtifacts() {
unset inbox sshCommand exitCode cmdOutput
s ilocal -A VENDOR=(
['FTPBASE']="/home/user"
['FTPSOURCEDIR']="/home/user/inbox/imaging"
['FRIENDLYNAME']="user"
['ENVIRONMENT']="dev"
)
inbox="${VENDOR['FTPBASE']}/inbox"
printf -v sshCommand "find -L %s \( ! -path %s -a ! -path '%s/*' -a ! -path %s -a ! -path '%s/*' \) -ls" \
"${inbox}" "${inbox}" "${inbox}" "${VENDOR['FTPSOURCEDIR']}" "${VENDOR['FTPSOURCEDIR']}"
#cmdOutput=$(ssh ${SSHOPTIONS} ${SSHUSERHOST} "${sshCommand}" 2>&1)
cmdOutput=$("${sshCommand}")
exitCode="${?}"
if (( 0 != $exitCode )); then
printf "FAILED - sshCommand=[%s], exitCode=[%d], cmdOutput=[%s]\n" "${sshCommand}" "${exitCode}" "${cmdOutput}"
exit 1
fi
printf "SUCCEEDED - sshCommand=[%s] exitCode=[%d]\n" "${sshCommand}" "${exitCode}"
printf "%s\n\n" "${cmdOutput}"
} # end findInvalidArtifacts()
And, finally, running the script with bash -vx -
#!/usr/bin/env bash
function findInvalidArtifacts() {
unset inbox sshCommand exitCode cmdOutput
local -A VENDOR=(
['FTPBASE']="/home/user"
['FTPSOURCEDIR']="/home/user/inbox/imaging"
['FRIENDLYNAME']="user"
['ENVIRONMENT']="dev"
)
inbox="${VENDOR['FTPBASE']}/inbox"
printf -v sshCommand "find -L %s \( ! -path %s -a ! -path '%s/*' -a ! -path %s -a ! -path '%s/*' \) -ls" \
"${inbox}" "${inbox}" "${inbox}" "${VENDOR['FTPSOURCEDIR']}" "${VENDOR['FTPSOURCEDIR']}"
#cmdOutput=$(ssh ${SSHOPTIONS} ${SSHUSERHOST} "${sshCommand}" 2>&1)
cmdOutput=$("${sshCommand}")
exitCode="${?}"
if (( 0 != $exitCode )); then
printf "FAILED - sshCommand=[%s], exitCode=[%d], cmdOutput=[%s]\n" "${sshCommand}" "${exitCode}" "${cmdOutput}"
exit 1
fi
printf "SUCCEEDED - sshCommand=[%s] exitCode=[%d]\n" "${sshCommand}" "${exitCode}"
printf "%s\n\n" "${cmdOutput}"
} # end findInvalidArtifacts()
findInvalidArtifacts
findInvalidArtifacts
unset inbox sshCommand exitCode cmdOutput
VENDOR=(['FTPBASE']="/home/user" ['FTPSOURCEDIR']="/home/user/inbox/imaging" ['FRIENDLYNAME']="user" ['ENVIRONMENT']="dev")
local -A VENDOR
inbox=/home/user/inbox
printf -v sshCommand 'find -L %s \( ! -path %s -a ! -path '\''%s/*'\'' -a ! -path %s -a ! -path '\''%s/*'\'' \) -ls' /home/user/inbox /home/user/inbox /home/user/inbox /home/user/inbox/imaging /home/user/inbox/imaging
'find -L /home/user/inbox \( ! -path /home/user/inbox -a ! -path '\''/home/user/inbox/*'\'' -a ! -path /home/user/inbox/imaging -a ! -path '\''/home/user/inbox/imaging/*'\'' \) -ls'
./try.sh: line 16: find -L /home/user/inbox \( ! -path /home/user/inbox -a ! -path '/home/user/inbox/*' -a ! -path /home/user/inbox/imaging -a ! -path '/home/user/inbox/imaging/*' \) -ls: No such file or directory
cmdOutput=
exitCode=127
(( 0 != 127 ))
printf 'FAILED - sshCommand=[%s], exitCode=[%d], cmdOutput=[%s]\n' 'find -L /home/user/inbox \( ! -path /home/user/inbox -a ! -path '\''/home/user/inbox/*'\'' -a ! -path /home/user/inbox/imaging -a ! -path '\''/home/user/inbox/imaging/*'\'' \) -ls' 127 ''
FAILED - sshCommand=[find -L /home/user/inbox \( ! -path /home/user/inbox -a ! -path '/home/user/inbox/*' -a ! -path /home/user/inbox/imaging -a ! -path '/home/user/inbox/imaging/*' \) -ls], exitCode=[127], cmdOutput=[]
exit 1
This is a stumper. I cannot see where why find is complaining about 'no such file or directory'.
Appreciate the valiant effort, however the constructed command still does not return the desired results. The contents of finding all existing artifacts in /home/user/inbox are:
/home/user/inbox
/home/user/inbox/invalidDir2
/home/user/inbox/invalidDir2/invalidSubdir2
/home/user/inbox/invalidDir2/invalidSubdir2/invalidFile1
/home/user/inbox/invalidDir2/invalidSubdir2/invalidSubSubDir2
/home/user/inbox/invalidDir2/invalidSubdir2/invalidSubSubDir2/invalidSubSubSubDir2
/home/user/inbox/invalidDir2/invalidSubdir2/invalidSubSubDir2/invalidSubSubSubDir2/invalidSubSubSubSubDir2
/home/user/inbox/invalidDir2/invalidSubdir2/invalidSubSubDir2/invalidSubSubSubDir2/invalidSubSubSubSubDir2/invalidFile
/home/user/inbox/invalidDir2/invalidSubdir2/invalidSubSubDir2/invalidSubSubSubDir2/invalidFile
/home/user/inbox/invalidDir2/invalidSubdir2/invalidSubSubDir2/invalidFile
/home/user/inbox/imaging
/home/user/inbox/imaging/validFile
/home/user/inbox/imaging/invalidFile
/home/user/inbox/imaging/invalidImagingDir1
/home/user/inbox/imaging/invalidImagingDir1/invalidSubdir1
/home/user/inbox/imaging/invalidImagingDir1/invalidSubdir1/invalidFile1
/home/user/inbox/imaging/invalidImagingDir1/invalidSubdir1/invalidSubSubDir1
/home/user/inbox/imaging/invalidImagingDir1/invalidSubdir1/invalidSubSubDir1/invalidSubSubSubDir1
/home/user/inbox/imaging/invalidImagingDir1/invalidSubdir1/invalidSubSubDir1/invalidSubSubSubDir1/invalidFile
/home/user/inbox/imaging/invalidImagingDir1/invalidSubdir1/invalidSubSubDir1/invalidFile
/home/user/inbox/imaging/invalidImagingDir1/invalildFile
/home/user/inbox/invalidFile
/home/user/inbox/invalidDir1
/home/user/inbox/invalidDir1/invalidSubdir1
/home/user/inbox/invalidDir1/invalidSubdir1/invalidFile1
/home/user/inbox/invalidDir1/invalidSubdir1/invalidSubSubDir1
/home/user/inbox/invalidDir1/invalidSubdir1/invalidSubSubDir1/invalidSubSubSubDir1
/home/user/inbox/invalidDir1/invalidSubdir1/invalidSubSubDir1/invalidSubSubSubDir1/invalidFile
/home/user/inbox/invalidDir1/invalidSubdir1/invalidSubSubDir1/invalidFile
The result set should NOT contain anything matching the directory to search in, or any of the parameters passed to your function that constructs the command. Results should NOT contain these lines -
/home/user/inbox
/home/user/inbox/imaging
/home/user/inbox/imaging/validFile
The command your function constructs looks like this -
find -L /home/user/inbox '(' '!' -path /home/user/inbox -a '!' -path '/home/user/inbox/*' -a '!' -path /home/user/inbox/imaging -a '!' -path '/home/user/inbox/imaging/*' ')' -ls
which returns nothing at all
I'm beginning to think that the find command is not what I need to obtain the desired results and that I'll need to do some more processing of the result set to disclude, probably awk or something.
CodePudding user response:
Relevant snippet:
printf -v sshCommand "find -L %s \( ! -path %s -a ! -path '%s/*' -a ! -path %s -a ! -path '%s/*' \) -ls" [more args]
cmdOutput=$("${sshCommand}")
This is a classic pitfall of trying to shove a command into a variable and run it. The basic solution is to use a function, not a variable.
The reason for your error is that Bash determines the name of the command you're trying to run by selecting the first word of the command line after completing all of its parsing steps. You want to use the command find
with some arguments, but since you have "${sshCommand}"
in quotes, there's only one word in the entire command line so Bash thinks the command you want is called find -L /home/dir ( ! -path etc etc... )
. I bet you don't have any executables with that name on your system.
A function equivalent of what you're trying to do might look like:
_findCmd() {
searchDir=$1 # first arg is the directory to search from
shift
# each extra argument is a directory to exclude from the search
# we can loop over the list and build the arguments that find needs
# in an array
path_args=()
if (( $# > 0 )) ; then
path_args =( "(" "!" "-path" "$1" )
shift
while (( $# > 0 )) ; do
path_args =( "-a" "!" "-path" "$1" )
shift
done
path_args =( ")" )
fi
find -L "$searchDir" "${path_args[@]}" -ls
}
cmdOutput=$( _findCmd /home/user/inbox /home/user/inbox "/home/user/inbox/*" /home/user/inbox/imaging "/home/user/inbox/imaging/*" )
CodePudding user response:
Putting aside the correct escaping of ssh remote commands, here's a remark about your find
command
find -L /home/user/inbox ! -path '/home/user/inbox/*'
Excludes any path that starts with /home/user/inbox/
(leaving only one possible match which is /home/user/inbox
).
Also, for excluding /home/user/inbox/imaging/validFile
while including /home/user/inbox/imaging/invalidFile
, using ! -path '/home/user/inbox/imaging/*'
is wrong, for the same reason as above.