I have a script with the following command to upload a bunch of zip files to a site:
find . -name "*.zip" -exec echo {} \; -exec sh -c 'err=$(curl -s --data-binary "@{}" http://mystorage.com | jq -r ".error"); if [ -z $err ] || [ $err = "file already exists" ]; then exit 0; else exit 1; fi' \;
The intention is that if any file fail to upload with the reason other than "file already exists" then the script must fail. However, if i run this command alone, it never exit with 1. My guess is that the subshell opened in the 2nd -exec returns 1 but the -exec ignore the return status and return 0 for the whole find command. Is there a way to make my command fail when the subshell fail?
CodePudding user response:
I wouldn't bother with find
for this. Just use an ordinary loop (with the globstar
option to search recursively, if necessary).
shopt -s globstar nullglob
for f in **/*.zip; do
err=$(curl -s --data-binary "@$f" http://mystorage.com | jq -r ".error")
if [ -n "$err" ] && [ "$err" = "file already exists" ]; then
exit 1
fi
done
Note that you don't want to exit 0 when the first job succeeds; just do nothing and let the next file be uploaded.
CodePudding user response:
You need to look at the four exec forms find
can use:
https://www.man7.org/linux/man-pages/man1/find.1.html
-exec command {} \;
-exec command {} \
-execdir command {} \;
-execdir command {} \
They all have different behaviors regarding their boolean value in the search boolean expression.
My brief interpretation (I have only read the manpages, I have not actually tried this):
Commands that end with a semicolon result in the -exec term having a true or false value, and do not effect the exit value of find even when the wrapped command has a nonzero exit value.
Commands that end with a plus cause find to exit with a nonzero value when a wrapped command has a nonzero result value.
So I think you want to switch to the -exec form where the command ends with a ' '.
But really I think you need a better multithreaded script that can handle each failure separately, and remember which ones it has successfully uploaded.
CodePudding user response:
Using GNU find:
find . -name '*.zip' -print -exec sh -c '
err=$(curl -s --data-binary "@$1" http://mystorage.com | jq -r ".error")
[ -z "$err" ] || [ "$err" = 'file already exists' ] || exit 1
' _ {} \; \
-o -quit
Note that this exits if .error
is empty. That may be what you want, but maybe you want this (or similar):
find . -name '*.zip' -print -exec sh -c '
response=$(curl -s --data-binary "@$1" http://mystorage.com) || exit 1
[ "$response" ] || exit 1
[ "$(echo "$response" | jq -r .error)" = 'file already exists' ] && exit 1
' _ {} \; \
-o -quit
Now it exits prematurely if curl fails, if the response is empty, or if .error
matches.