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, 2013 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, 2013 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, 2013 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, 2013 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, 2013 at 23:37

2 Answers 2

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, 2013 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, 2013 at 16:46

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .