• tetris11@lemmy.ml
    link
    fedilink
    arrow-up
    3
    ·
    15 hours ago

    Oh I see it, but for some reason I was taught to always use $(( arith )) instead of (( arith )) and I guess I’m just wondering what the difference is

    • balsoft@lemmy.ml
      link
      fedilink
      arrow-up
      6
      ·
      edit-2
      14 hours ago

      The difference is that (( is a “compound command”, similar to [[ (evaluate conditional expression), while $(( )) is “aritmetic expansion”. They behave in almost exactly the same way but are used in different contexts - the former uses “exit codes” while the latter returns a string, so the former would be used where you would expect a command, while the latter would be used where you expect an expression. A function definition expects a compound command, so that’s what we use. If we used $(( )) directly, it wouldn’t parse:

      $ even() $((($1+1)&1))
      bash: syntax error near unexpected token `$((($1+1)&1))'
      

      We would have to do something like

      even() { return $(($1&1)); }
      

      (notice how this is inverted from the (( case - (( actually inverts 0 -> exit code 1 and any other result to exit code 0, so that it matches bash semantics of exit code 0 being “true” and any other exit code being “false” when used in a conditional)

      But this is a bit easier to understand and as such wouldn’t cut it, as any seasoned bash expert will tell you. Can’t be irreplaceable if anyone on your team can read your code, right?

      I can’t think of many use-cases for ((. I guess if you wanted to do some arithmetic in a conditional?

      if (( $1&1 )); then echo "odd!"; else echo "even!"; fi
      

      But this is pretty contrived. This is probably the reason you’ve never heard of it.

      This (( vs. $(( )) thing is similar to how there is ( compound command (run in a subshell), and $( ) (command substitution). You can actually use the former to define a function too (as it’s a compound command):

      real_exit() { exit 1; }
      fake_exit() ( exit 1 )
      

      Calling real_exit will exit from the shell, while calling fake_exit will do nothing as the exit 1 command is executed in a separate subshell. Notice how you can also do the same in a command substition (because it runs in a subshell too):

      echo $(echo foo; exit 1)
      

      Will run successfully and output foo.

      (( being paired with $((, and ( with $(, is mostly just a syntactic rhyme rather than anything consistent. E.g. { and ${ do very different things, and $[[ just doesn’t exist.

      Bash is awful. It’s funny but also sad that we’re stuck with it.