News for hackers. Stuff that matters.
Re:Write Posix Shell by ra1231963 on Saturday March 11, 2023 @10:56AM (#35109358)
This is terrible advice. Senior people say don’t do this because they’ve seen it done and it’s an absolute nightmare (I’ve seen it happen multiple times).

It’s untyped, untestable, arcane, and unmaintabale. Even the link says don’t do this. Just don’t.

Congrats on having the chops (and neckbeard) to pull this off. If you want to do it in a personal project, more power to you. But it doesn’t scale at organizations.

Re:Write Posix Shell by jmmv on Saturday March 11, 2023 @11:03AM (#35109441)
Anyone writing code in a language they don't know will write nightmarish code. No matter if it is shell, Python, Go, or what have you. I have seen it happen multiple times as well, with all of these languages. And /that/'s the problem.

So, it depends on the context. "Organization" is a very broad term. If the team you are in is familiar with the shell, and the shell is the right tool for the job, there isn't that much of a problem.

I'm not arguing for writing large shell scripts when there are better alternatives. But, sometimes, it's the right choice and it can be written properly. And even if it isn't... 500 lines of poorly written shell aren't that many in any case, and they aren't that bad compared to 5000 lines of poorly written Python for example.

Re:Write Posix Shell by kaba0 on Saturday March 11, 2023 @11:28AM (#35109770)
I fail to see why you think it would take more lines to do in Python.

And the problem with bash is similar to C: many people think they can write correct C code, but as it has been shown plenty of times, that doesn’t really work out in the end. Languages have different tradeoffs and bash really has no redeeming qualities, imo.

Re:Write Posix Shell by mananaysiempre on Saturday March 11, 2023 @11:47AM (#35110043)
> I fail to see why you think it would take more lines to do in Python.

Because Bourne shell is not a Python-class language like Ruby or perhaps even Scheme or AWK are. Things that are easy in shell can be hard in Python and vice versa: awkward wrangling of subprocess.Popen in Python can be a single line of shell; simple tree munging with lxml in Python can easily be a hundred or more lines of wasteful xmlstarlet invocations in shell. Parallel processing, even without the heavy artillery of make or GNU parallel, is easy in shell but hard in Python. Structured data is hard in shell but easy in Python.

(Similarly, I wouldn’t use ML or Haskell to write a web scraper, and I wouldn’t use Python to write a compiler.)

Re:Write Posix Shell by patrakov on Saturday March 11, 2023 @12:14PM (#35110357)
Regarding parallel processing, I have to disagree. It is bad in shell, because it makes best practices such as "set -e" impractical. The usual failure mode is a script that does not stop correctly on SIGTERM, and its children have to be hunted down and killed separately.
Re:Write Posix Shell by mananaysiempre on Saturday March 11, 2023 @04:59PM (#35113225)
That’s fair.

Perhaps a better way to put it would be that sloppy concurrency is easy. This doesn’t sound all that good, but it’s easy enough that I find myself parallelizing one-off things in shell that would be such a hassle to do nonsequentially in Python (compared to the magnitude of the problem) that the option wouldn’t even surface in my brain. (If I rewrite the shell script in Python later, the rewritten version is often sequential.)

The shell error handling story for “run stream processing steps in lockstep” parallelism is much better than for “spawn a bunch of identical children” parallelism, though, and that’s often enough.

Re:Write Posix Shell by hedora on Saturday March 11, 2023 @12:18PM (#35110401)
I’ll bite. Show me the equivalent of this in python, including error handling, parallelism, disk footprint, and real-time status output:

   #!/bin/bash -eux -o pipefail

   TMPDIR=$(mktemp -d tempdirXXXXX)
   trap “rm -rf $TMPDIR” SIGINT SIGTERM ERR EXIT
   (
      cd $TMPDIR
      foo | grep x > foo.out & 
      bar > bar.out & 
      baz $TMP | tee baz.out &
   )
   wait

   tar -cf - -C $TEMPDIR | zstd -6 -z - | pv | ssh server.com bash -c “cat - > out.tag.zstd”
Re:Write Posix Shell by EuAndreh on Saturday March 11, 2023 @12:34PM (#35110571)
You can forego the final "bash -c" by leveraging dd(1) to avoid the redirection problem:

    ... | ssh server.com dd of=out.tag.zstd
Re:Write Posix Shell by hedora on Saturday March 11, 2023 @12:38PM (#35110607)
Thanks! Will definitely use that moving forward.
Re:Write Posix Shell by EuAndreh on Saturday March 11, 2023 @12:37PM (#35110596)
dd(1) reads from STDIN by default unless given an "if=" parameter, and writes to STDOUT by default umless given an "of=" parameter.
Re:Write Posix Shell by _dain_ on Saturday March 11, 2023 @12:37PM (#35110602)

    $ shellcheck myscript
     
    Line 1:
    #!/bin/bash -eux -o pipefail
    ^-- SC2096 (error): On most OS, shebangs can only specify a single parameter.
     
    Line 4:
    trap "rm -rf $TMPDIR" SIGINT SIGTERM ERR EXIT
                 ^-- SC2064 (warning): Use single quotes, otherwise this expands now rather than when signalled.
     
    Line 6:
          cd $TMPDIR
             ^-- SC2086 (info): Double quote to prevent globbing and word splitting.

    Did you mean: (apply this, apply all SC2086)
          cd "$TMPDIR"
     
    Line 9:
          baz $TMP | tee baz.out &
              ^-- SC2086 (info): Double quote to prevent globbing and word splitting.

    Did you mean: (apply this, apply all SC2086)
          baz "$TMP" | tee baz.out &
     
    Line 13:
    tar -cf - -C $TEMPDIR | zstd -6 -z - | pv | ssh server.com bash -c "cat - > out.tag.zstd"
                 ^-- SC2086 (info): Double quote to prevent globbing and word splitting.
                 ^-- SC2153 (info): Possible misspelling: TEMPDIR may not be assigned. Did you mean TMPDIR?

    Did you mean: (apply this, apply all SC2086)
    tar -cf - -C "$TEMPDIR" | zstd -6 -z - | pv | ssh server.com bash -c "cat - > out.tag.zstd"
Re:Write Posix Shell by Too on Sunday March 12, 2023 @04:08AM (#35117905)
Python wins the triathlon by being second best in every game. Piping things between programs is about the only thing bash is good at, nothing else, of course it is going to look good when unconditional straight piping things through standard programs is the only requirement. It's like saying c++ is fastest at calculating pi, duh, nobody will argue against that. Now, instead, put that script into a bigger context where some actual program logic or other integrations are needed. It is going to explode in unreadability, bugs and only supporting happy-cases. It is only simple if your original problem is simple.
Re:Write Posix Shell by Zacru on Sunday March 12, 2023 @06:09PM (#35126950)
I like both Bash and Python, so I think I'll give this a try. Should I implement the bugs as is, or fix those first?
Re:Write Posix Shell by mattpallissard on Saturday March 11, 2023 @11:54AM (#35110130)
> Anyone writing code in a language they don't know will write nightmarish code. No matter if it is shell, Python, Go, or what have you. I have seen it happen multiple times as well, with all of these languages. And /that/'s the problem.

Came here to say this.

Re:Write Posix Shell by IshKebab on Sunday March 12, 2023 @01:25PM (#35123074)
You're implying that all languages are equally likely to produce buggy programs. That's clearly false. There's a spectrum.

At one end you have things like Haskell, OCaml, Rust, (or if you go really extreme Dafny etc.).

At the other end you have Bash.

There's no way a 500 line Bash script would require 5000 lines of Python.

Re:Write Posix Shell by hedora on Saturday March 11, 2023 @11:57AM (#35110165)
Python is untyped and untestable. The only way I’ve seen people use it is by importing whatever libraries were popular in whatever year they wrote it, so it’s also arcane.

Also, to understand someone else’s python, you have to read at least 10x more lines of line noise, so it somehow manages to be less maintainable than shell.

Concrete example: Every python code base I’ve encountered has some function named exec that poorly reimplements shell job control and argument passing. As the python code bases grow, they end up with more than one of these, all of which have different bugs.

I usually discover this about 6 hours after the script has been sent to me, since someone who has heard the words “supply chain vulnerability” locked down whatever machine I need to run the script on.

The last ten times this has happened (at multiple companies, with multiple teams) it ended up being faster to figure out what shell commands the python script wanted to invoke, port a few things to jq and then reimplement the rest in a mix of shell and perl.

The result is always 1-10% the lines of code of the python, and actually runs without downloading an entire python distribution, dependency manager, and hundreds of broken packages at runtime.

Re:Write Posix Shell by _dain_ on Saturday March 11, 2023 @12:40PM (#35110642)
>Python is untyped and untestable.

Completely untrue. You're conflating static typing with strong typing. And pytest is a great test framework.

And you're recommending shell for better typing and testability? The language where everything is a string and there are no proper arrays? You have to be trolling.

Re:Write Posix Shell by oweiler on Saturday March 11, 2023 @02:03PM (#35111450)
On top of that, fn in Bash can only return their status code. Yes, command substitution exists but is full of footguns.
Re:Write Posix Shell by hedora on Saturday March 11, 2023 @08:18PM (#35115167)
I’ve probably spent two weeks (80+ active hours) debugging stuff like ‘“” is not None’. At this point, I’d prefer a language with only string types to one that only checks types in production.

pytest is terrible, at least from how I’ve seen people use it. It hides the diagnostic error explaining why the test failed in a random place. Its output is not parseable. If you have a long running test that times out, then it buffers the stdout and stderr so you have to wait for the fallback test time out every. single. time.

Re:Write Posix Shell by Too on Sunday March 12, 2023 @03:52AM (#35117815)
You've got exactly same problem of undefined vs empty in sh (-n not being exact inverse of -z vs string comparision with != "", different behavior if -u is set, etc). Just check the stackoverflow answers on how to test if a bash string is empty or undefined and there isn't even consensus on what is the best way to do it.

Mypy has had strict Optional checking on as default since 2018, almost entirely eliminating any None-related errors, meaning it is actually stricter and safer than Java or other traditionally considered static languages in that regard, (bar any dynamic misuse in deserialization boundaries). Assuming you use mypy of course, but that's a given today imo, like using shellcheck is for sh.