cross-posted from: https://lemmy.ml/post/39334581

you are viewing a single comment's thread
view the rest of the comments
[–] 21 points 9 months ago (4 children)

Not sure I'd call what bash has functions. They're closer to subroutines in Basic than functions in other languages, as in you can't return a value from them (they can only return their exit code, and you can capture their stdout and stderr). But even then, they are full subshells. It's one of the reasons I don't really like Bash, you're forced into globally or at least broadly-scoped variables. Oh, and I have no clue right now how to find where in your pipe you got a non-null exit code.

It's not a big problem for simple scripting, but it makes things cumbersome once you try to do more.

  • source
  • hideshow 8 child comments
  • [–] 6 points 9 months ago (2 children)

    I really like bash when dealing with even somewhat advanced scripting. Like the 300 LOC scraper I have written over the past two days which horribly parses HTML files using grep | sed.

    It's genuinely so much more fun to do this with Bash than, say, Python. I have once written a scraper using Beautifulsoup and I have no desire to do so ever again.

    Honestly, only Haskell manages to beat Bash in how satisfying it feels when you manage to get something working well.

  • source
  • parent
  • hideshow 4 child comments
  • [–] 2 points 9 months ago

    Bash has its upsides too, like the fact that it has arrays / lists and dictionaries / hashmaps. In my opinion, it gets iffy though when you need to do stuff with IFS; at that point one might be better off just using specialized tools.

    Not saying working bash isn't good enough, but it can break in very surprising ways is my experience.

  • source
  • parent
  • [–] 4 points 9 months ago (2 children)

    You're not forced into global forced variables, but they're the default. Use the local keyword in front of the variable declaration for nicely scoped variable.

    It's not that cumbersome to do things like

    local date=`date`
    echo "$date"
    

    but in all honesty the syntax sucks ass because it's not intuitive. If statements suck ass, passing variables has to be done via command line arguments sucks ass, switch statements suck ass, making structured data sucks ass (jq is nice though).

    I agree with you that bash really sucks when you get to anything more than 10 lines and at that point I'd take literally prefer Dreamberd.

  • source
  • parent
  • hideshow 4 child comments
  • [–] 1 point 9 months ago (1 child)

    I didn't mean that bash has no local variables, but rather that if you want to use a function as such without capturing stdout, you need variables that are scoped across your functions, which is usually global or at least effectively global.

  • source
  • parent
  • hideshow 2 child comments
  • [–] 1 point 9 months ago (1 child)

    Turns out you can, by using () instead of {} in the function declaration you can run the function in a subshell where changes to variables are scoped to the subshell and functions are local.

  • source
  • parent
  • hideshow 2 child comments
  • [–] 4 points 9 months ago* (2 children)

    Functions are definitely not subshells in Bash, seeing as anything modifying the environment, like pyenv and such, is implemented as functions instead of scripts — specifically because functions are run in the same shell instance.

    Unless 'subshell' means something in the vein of 'like a new shell, but not really'.

  • source
  • parent
  • hideshow 4 child comments
  • [–] 1 point 9 months ago (1 child)

    Try doing cd inside a function and then pwd in the main script. Does it move the main script too?

  • source
  • parent
  • hideshow 2 child comments
  • [–] 1 point 9 months ago* (last edited 9 months ago)

    I'm gonna bet yes for the simple reason that various helper scripts exist that do advanced cd history, with fuzzy search and whatnot, and they can't be implemented as anything other than functions.

  • source
  • parent
  • [–] 3 points 9 months ago*

    where in your pipe you got a non-null exit code

    First thing you want is set -e and set -o pipefail. That should report the errors in human-parseable form.

    Second, to capture exit codes from each command/program, you have to run each of them in sequence yourself, connected by pipes that you create via mkfifo — the same way as you would do it in any other programming environment. Bash's | pipes are just a convenient shorthand for this,so if you want full control, you have to ditch the convenience.

  • source
  • parent