0

I have a shell script which executes on a CI server , the shell script does a couplr of Curl's . Now i would want the script to fail if the curl is unsuccessfull, I read that "$?" will give the status of the statement executed , how do i use this to achieve what i want ?

function do_curl 
    {
      echo "==== Posting $file_name to DHIS ===="
      curl -H "Content-Type: application/json" -u $authorization -d @$file_name $url -X POST || exit
      echo ""
    }

this function is called repeatedly , i want it to exit even when it fails the first time , right now , it does not exit , but executes the number of times its called , even though it fails the very first time.

user1537766
  • 162
  • 7
  • Not good enough. Putting `|| exit` on a call inside a function *will* exit shell, not just the function, so again, you still have a subshell somewhere, presumably **outside** of the function itself. – Charles Duffy Mar 20 '14 at 16:46
  • By the way, `function foo {` is not the POSIX compliant way to define a function. Use `foo() {`, with no `function` keyword, if you want your code to be compatible with other shells. – Charles Duffy Mar 20 '14 at 16:46
  • Also, you need more quotes to avoid string-splitting. `-u "$authorization"`, `-d "@$file_name"`, `"$url"`, etc, or you'll get bugs whenever your filenames, authorization content, etc. contains spaces, glob characters, etc. – Charles Duffy Mar 20 '14 at 16:47
  • By the way -- are you sure curl is actually exiting with a nonzero value? You may need to use `curl --fail` if you're getting, say, a 500 error but still exiting with status 0. – Charles Duffy Mar 20 '14 at 16:48
  • As in my updated answer, you will probably find what you're looking for here: http://stackoverflow.com/questions/9893667/using-exit-in-bash-functions – griffin Mar 20 '14 at 16:48
  • @griffin ...well, if we get confirmation of that, we can mark this for close-as-dupe. No point in changing answers until it's confirmed. – Charles Duffy Mar 20 '14 at 16:50
  • @charles , i will take your suggestion of string-splitting :) – user1537766 Mar 20 '14 at 17:08
  • @griffin , i did try what you pointed out , it did not work for me , it was , as previously mentioned , was terminating after executing the statement multiple times. – user1537766 Mar 20 '14 at 17:10
  • @user1537766 that's why I updated my answer with a link to another question which, as you pointed out later, seems to have been the exact problem you've been experiencing. Anyway, good you got your answer now - for completeness sake it would be good if you noted that somewhere besides a comment (e.g. update your question or ask charles to put it into his answer) – griffin Mar 21 '14 at 01:23

2 Answers2

2
curl --fail ... || exit

...will immediately exit the shell script with curl's exit status in the event that said curl call fails.

It's also possible to get exit-on-failure behavior globally with set -e, but this should only done by experts; see http://mywiki.wooledge.org/BashFAQ/105 for a discussion of its limitations and pitfalls.

Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
  • I tried it , it does not work , what it does is , it throws out an error on the console , but nonetheless goes ahead and executes the other statements also. – user1537766 Mar 20 '14 at 16:42
  • 1
    @user1537766, if that's the case, you're running inside a subshell, and need to exit not just the immediate shell but its parent(s) as well, or to restructure your code to no longer spawn a subshell at all. In any of these cases, we'd need more context to be helpful. – Charles Duffy Mar 20 '14 at 16:44
  • You were right , i was spawning a subshell , it works like charm now ! thanks ! – user1537766 Mar 20 '14 at 17:05
2

Update:

For a possible answer to your question using functions (the original question did not have a function), see here: Is there a way to write a bash function which aborts the whole execution, no matter how it is called?

(you can also update your question further to get better answers)


One possible solution would be using something like this for every line:

curl ... || exit

Of course, if you have multiple urls, you can encapsulte that in a function for example, or you could chain them this way:

curl ... && curl ... && ...

You can also break the current line using \ like this:

curl ... && \
curl ... && \
...

This also works because a script without explicit exit statement should return the last set exit code, e.g. the one returned by the last executed curl command in this case.


Regarding the used operators:

a || b 

Means: evaluate a OR b, and the || is logically applied to the return code of a, so if a returns 0 or something not 0, b will be executed anyway.

a && b

Means: execute a AND b, and the && is again logically applied to the return code of a, so if a returns 0 (=false), b won't be executed as the evaluation will stop at that point, but if a returns a value not 0 (=true), evaluation and thus execution will continue.

You can additionally combine this with subshells using parantheses (( and )) and other stuff to build some quite complex command chains, but I would advise to follow the KISS ("Keep it simple, stupid!") principle in case of shell scripts and better write everything on their own line, additionally commenting ( using # ), so you still know what the script does if you have to look at it a year later ;)

While these things have been the same on all the shells I've used so far, there can still be differences, but if you, like me, have bash on most machines, this might be interesting to you:

Bash Reference Manual

Community
  • 1
  • 1
griffin
  • 1,261
  • 8
  • 24
  • There's no reason to explicitly pass `$?`; `exit` uses `$?` implicitly. – Charles Duffy Mar 20 '14 at 16:33
  • @CharlesDuffy you're just faster with commenting than I'm with finishing my edits ;) but thx for pointing that out ;) – griffin Mar 20 '14 at 16:33
  • Please, **please** don't point people at the ABS. I swear that half our job in Freenode's #bash channel is helping people unlearn bad habits they picked up there. – Charles Duffy Mar 20 '14 at 16:51
  • @CharlesDuffy while I don't really get the problem with the ABS, I've now replaced the pointer with one to the bash reference manual which also helps (though IMHO you need more time to find what you're looking for normally than in the ABS) – griffin Mar 21 '14 at 01:20
  • If you want a reference that's actively maintained by people who care about accuracy, I'd suggest http://mywiki.wooledge.org/BashGuide. The ABS's maintainership has been frequently absentee, and has a history of ignoring complaints about examples which contradict best-practices. – Charles Duffy Mar 21 '14 at 01:46
  • ...so, I opened up a random page and started looking for problems. http://www.tldp.org/LDP/abs/html/subshells.html shows (1) using `sh` to execute scripts with a `bash` shebang; (2) using `[ 1 ]` as an example of an always-true test (the more portably efficient alternative is `:`); (3) uses an explicit `exit $?` -- which has an implications contrary to `exit`s true default behavior of using `$?` implicitly... and that's without even scrolling down. – Charles Duffy Mar 21 '14 at 01:51
  • ...oh -- there's also an example that greps through `ps` on that first page, where's the best practice is to avoid doing that in favor of tools such as pgrep, and that shell with a non-POSIX shebang is using a .sh extension. – Charles Duffy Mar 21 '14 at 01:52