5

I'm used to this style in other languages:

do_something || (log_error; return 1) # do something, and if that fails, log the error and then return 1 no matter what, even if the logging fails.

But I can't seem to find an equivalent in bash. The problem is that the parenthesis work kind of like a function with its own scope, and the return 1 won't have the expected behavior.

This is what I have so far, but it's not perfect:

! do_something && log_error && return 1

The problem with this is that the ! is confusing, and the return 1 depends on the success of the logging.

This one is better, but more verbose:

do_something || (log_error; return 1) || return 1

Any thoughts?

6
  • The return statement is meaningful only when inside a script or function - not on the command line. Who do you want to return 1 to?
    – user111228
    Jan 12 '13 at 16:29
  • @htor You are right, I always use this snippet inside a function. Because sometimes I need to include the script, and some other times I need to execute it as a standalone script. Jan 12 '13 at 17:18
  • @ChocoDeveloper: Use return to return from a shell function but continue executing the script from where it was called; use exit to exit the entire shell (i.e. the script). Unless you're in parentheses, in which case you're in a subshell and exit only exits the parenthesized (subshell) expression. Jan 12 '13 at 18:16
  • @GordonDavisson Yes, the problem is I have the payload of the script inside parenthesis (outside I only have some vars and functions I always use), to redirect the stdout/stderr (most times I want both) to a log file, and exit stopped that redirection last time I tried. That way I can have each script dealing with its own logs, instead of doing that from the caller (eg, from the cli, or a cron file). Jan 12 '13 at 20:51
  • 1
    @ChocoDeveloper: Since each script (normally) runs as a separate shell, you can redirect with e.g. exec >output.log 2>error.log and it won't mess up the calling script. Or you can use { payload; } >output.log 2>error.log and the redirect will only apply to what's in the brackets, without needing a subshell. Jan 12 '13 at 23:37
11

Use braces.

 do_something || { log_error; return 1;}
0
1

The exit status of the last command run is saved in the $? variable. So, you could do something like the following:

do something
if [[ $? > 0 ]]; then 
   do log_error; exit 1; 
fi

I like that for readability's sake. However, yours is perfectly good, you just need to replace && with ;:

! do_something && log_error ; return 1

&& means "execute the next command ONLY IF the previous one exited successfully" while ; just means "execute the next command".

2
  • In your second example, return 1 is executed in case of success.
    – BatchyX
    Jan 12 '13 at 16:38
  • As far as I can tell, it is executed in case of both success and failure as desired. The exit status of ! ls /etc && echo "FAIL" > ~/log ; return 1 AND of ls /etcaaa && echo "FAIL" > ~/log ; return 1 is 1.
    – terdon
    Jan 12 '13 at 16:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.