3
  • true && echo foo will print foo.
  • false && echo foo will not print foo.
  • bash -c "exit $a" && echo foo will print foo depending on $a.

Is there a more elegant way to write the last one? It seems a bit much having to start a shell simply to set the exit value. I am thinking something like:

  • return $a && echo foo
  • exit $a && echo foo

except return only works in functions and exit will cause echo foo never to be run.

Elegant in this context means:

  • Easy to understand
  • Portable
  • Easy to read
  • Easy to write
  • Easy to remember
  • Short
  • High performance

E.g. if true took the exit code as an argument (and this was a documented feature), it would be very elegant.

So is there a more elegant way?

Background

One of the places this could be used is for:

$ parallel 'setexitval {= $_%=3 =} || echo $?' ::: 0 1 2 3  

Kusalananda's version is probably the best. It is clear what is going on. It is not long and cumbersome to write. It is easy to remember and portable. The only drawback is that it forks another shell:

$ parallel '(exit {= $_%=3 =}) || echo $?' ::: 0 1 2 3  

Another situation is when you want to simulate an error condition. Say, if you have a long running program, that sets different exit codes, and you are writing something that will react to the different exit codes. Instead of having to run the long running program, you can use (exit $a) to simulate the condition.

closed as unclear what you're asking by mattdm, glenn jackman, Rui F Ribeiro, Wildcard, Michael Homer Feb 13 '18 at 0:35

Please clarify your specific problem or add additional details to highlight exactly what you need. As it's currently written, it’s hard to tell exactly what you're asking. See the How to Ask page for help clarifying this question. If this question can be reworded to fit the rules in the help center, please edit the question.

  • 4
    Your goal is to set $? to $a? – Jeff Schaller Feb 12 '18 at 21:00
  • 9
    Why? Why not just check the value of a? – mattdm Feb 12 '18 at 21:03
  • 6
    Can you define "elegant"? – mattdm Feb 12 '18 at 21:18
  • 6
    @OleTange Can you explain 3 things: 1) why do you want to use && there ? The whole purpose of && is to run based on exit status,which is either success or failure. There's really no need, because exit 1 or exit 2 or exit 3 all look exactly the same as false to && echo foo part. 2) If your definition of elegant is short, well Kusalananda's answer is as short as it gets although it's seems kinda redundant. 3) If you're trying to set $? ...why ? Can you explain the reasoning for need of such acrobatics ? – Sergiy Kolodyazhnyy Feb 12 '18 at 21:36
  • 9
    This question strongly smells like an "AB Problem" to me. There's a very good chance that whatever you're actually trying to accomplish that led you to wanting to manipulate the exit status could be more directly and more elegantly solved without having to manipulate the exit status this way. – mtraceur Feb 12 '18 at 22:19
7

Use a subshell that exits with the specified value.

This will output 5:

a=5; ( exit $a ) && echo foo; echo $?

This will output foo and 0 (note, this zero is set by echo succeeding, not by the exit in the subshell):

a=0; ( exit $a ) && echo foo; echo $?

In your shortened form (without visibly setting a or investigating $? explicitly):

( exit $a ) && echo foo

My answer is one that comes from just taking the question at face value and solving it as a curious quiz, "how may we set $? (using handy notation)". I make no attempt to search for any deeper meaning or function or even context in this case (because non was given). I additionally do not judge the validity, efficiency or usability of the solution. I sometimes, in my answers, do say things like "... but don't do that, because...", followed up with "instead, do this...". In this case, I'm choosing to interpret the question as simply a curious quiz.


Further background was now added to the question.

My take on the issue of forking a subshell is that scripts like GNU configure does this all the time, and that it's not terribly slow unless done in a really tight (long-running) loop.

I can't say much about the use of this in/with GNU parallel as I'm not a frequent user of that software.

  • Better and easier to understand than your last suggestion. – Ole Tange Feb 12 '18 at 21:26
  • 1
    @OleTange Yes, I agree with that. The (( !a )) thing was a bit fragile. This (above) is actually portable :-) – Kusalananda Feb 12 '18 at 21:28
  • 2
    @mtraceur I understand what you're saying, but I believe that the main point of the question was one of notation, and I interpreted the issue with "starting a shell" as "bach -c "exit $a" is too much to type". – Kusalananda Feb 12 '18 at 22:29
  • 1
    Sidenote: one advantage to this naked exit-in-subshell method (without a function of any sort) besides conciseness over the function-return method: radical portability to every Bourne-like shell, as far as I know. (Not that it makes a difference in practice, because every Bourne-like shell in remotely practical use today has proper functions without any of the downsides (like wiping global $@) that would effect this.) – mtraceur Feb 12 '18 at 22:42
  • 1
    On further thought, I'm giving this a +1, despite my initial crticism. Because OP asked for "elegant", and this is certainly a good answer for many people's definitions of "elegant". – mtraceur Feb 12 '18 at 22:49
12

Well, return works in a function, so let's make one:

$ ret() { return "${1-0}"; }
$ ret 1 || echo foo
foo
$ ret 123 ; echo $?
123

It needs a bit more setup than a subshell, but is shorter to use after that, and doesn't require forking a subshell.

  • I took a bit of inspiration out of your approach. Care to review my answer ? – Sergiy Kolodyazhnyy Feb 12 '18 at 23:16
  • IF that function had been part of Bash, I would find this more elegant than Kusalananda's answer. But having to define a function is around as cumbersome as using bash -c "exit $a". – Ole Tange Feb 13 '18 at 7:18
  • @OleTange, if you'd deigned to show the context where you needed this in the first place (or what the exact definition for elegance was), I wouldn't have suggested this. But you didn't, and I explicitly mentioned this needs more setup than running a subshell (namely, defining the function). I said "a bit" since only one line isn't much in a multiline script, but it obviously is too much for a one-liner. After that setup, it's much less cumbersome than bash -c "exit $a". – ilkkachu Feb 13 '18 at 9:32
4

One option (probably faster but not really more elegant):

test "$a" -eq 0 && echo foo

It executes echo but does not set the exit value to $a, so it is a mediocre solution.

4

Let's examine your assumptions:

  • true && echo foo will print foo. Correct because && adheres to AND with short circuit logic; because of left-associativity in && and || operators if left-most command returned success exit status 0 (which true does always) , the right-most command to this operator will run.

  • false && echo foo will not print foo. Exactly the opposite case of explained above.

  • bash -c "exit $a" && echo foo will print foo depending on $a. Essentially wrong assumption that $a controls &&. Because && is AND logic, it recognizes only two states - success or failure, where failure is any exit status above 0. Thus exit 1 and exit 2 and exit 3 - all are irrelevant to &&; failure is failure regardless of $a value; that is why echo foo doesn't run.

Therefore the answer is no, there is no more elegant way to do something that operates under wrong assumption anyway. However, if your purpose is to set exit status via command, that's sufficient to use what Kusalananda's answer suggests - a subshell. I personally don't see that any different from bash -c part, except that subshell may be implemented as child process/forked process instead of separate process; still not ideal. Note that $? also shouldn't be set by user via variable - it is intended for commands to communicate success or failure.

Let's switch focus on $a for a second. Why set $? and echo foo, if you can directly check $a ? It makes no sense to place $a value where it doesn't belong anyway, i.e. in $?. I would recommend shifting focus from "elegant"( whatever that means ) to "logical" and "working".


Alright, but let's play your game. Taking a modest inspiration from ilkkachu's answer. This approach, however, removes need to force echo conditional execution. It will go to echo if an only if it provided variable indicates success, and return prevents its execution.

$ thing(){ [ "${1-0}" -eq 0 ] || return "$1" ; echo "foo"; }
$ thing
foo
$ thing 0
foo
$ thing 1
$ echo $?
1
$ thing 2
$ echo $?
2

What may not be obvious is that you can do thing $a

  • +1: good tackling the probable conception underlying the question (especially given the limited insights the question actually gives into it). As an aside, I would suggest highlighting ilkkachu's answer at least as prominently as Kusalanda's, because the function route is more efficient and with the right function naming will be more readable than the naked subshell route (and while a function wrapper for the subshell method would gain the same readability advantage, it would lose the only advantages of conciseness and radical-portability-to-ancient-Bourne-shells). – mtraceur Feb 12 '18 at 22:31
  • 1
    @mtraceur Agreed, since ilkkachu's answer doesn't produce a separate process. Conceptually, though...even function seems as reinventing wheel where one even doesn't need a wheel – Sergiy Kolodyazhnyy Feb 12 '18 at 22:34
  • 1
    @Kusalananda And it's a decent answer, as always when it comes to your answers. Just the "quiz" itself seems to make wrong assumptions, which OP despite repeated comments did not clarify. We can set $?, it is indeed curious how to do it, but it doesn't mean it's intended to be set by the user. – Sergiy Kolodyazhnyy Feb 12 '18 at 22:54
  • @SergiyKolodyazhnyy And the decision I make there is to not care, at least not until I see it in some form of context. – Kusalananda Feb 12 '18 at 23:11
  • 1
    @Kusalananda I think in this decision you're probably wiser than most people here :) – Sergiy Kolodyazhnyy Feb 12 '18 at 23:16

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