[HN Gopher] Shfmt - format shell programs
       ___________________________________________________________________
        
       Shfmt - format shell programs
        
       Author : typical182
       Score  : 73 points
       Date   : 2023-02-11 17:08 UTC (5 hours ago)
        
 (HTM) web link (github.com)
 (TXT) w3m dump (github.com)
        
       | typical182 wrote:
       | shfmt is like gofmt, rustfmt, ..., but for shell programs.
       | 
       | Supports bash, posix, mksh, bats.
        
       | VWWHFSfQ wrote:
       | The caveats are somewhat of a deal breaker unfortunately. It
       | fails on perfectly valid syntax because they don't want to
       | complicate the parser. But that makes the tool not very useful.
        
         | Spivak wrote:
         | I can't say I've ever used the forms they don't support and I
         | am the person who uses all sorts of esoteric bash features at
         | work.
         | 
         | Also for static typing an analysis I would absolutely give up
         | even more syntax that is ambiguously parsed.
        
           | jamal-kumar wrote:
           | I throw all my shell scripts through this beast of a haskell
           | application to see if they're clean:
           | 
           | https://github.com/koalaman/shellcheck
           | 
           | Crucially it shows where on the line the error is in case
           | I've got some large piped one-liner which might have a
           | problem.
        
         | usr1106 wrote:
         | We have used it for more than a year in CI at work. We have
         | many dozens of scripts from various coders. Nobody has ever
         | complained that those caveats would have affected them. I was
         | not aware of them, needed to search now where they even are
         | (need to follow the more info link).
        
         | 2h wrote:
         | Have to agree with the other response. Demanding perfection is
         | not realistic in many situations. If you can get 95% of the way
         | there with 50% of the code/effort, you should do it. Sometimes
         | being productive is knowing when that last percentage just
         | isn't worth it.
        
         | mvdan wrote:
         | For the first two caveats, I actually agree that we could and
         | should handle ambiguous input. It just hasn't been a priority
         | because doing that properly would be quite a bit of work, and
         | such ambiguous syntax isn't particularly common. See
         | https://github.com/mvdan/sh/issues/686 for my current thoughts
         | on how to tackle it.
         | 
         | The third caveat concerns parsing `export` and `let` as
         | keywords rather than as builtins. Like the README says, this is
         | to properly build the syntax tree without leaving opaque
         | strings as expressions, but also to support `declare foo=(bar)`
         | which wouldn't work if `declare` was treated like any other
         | builtin simple command.
         | 
         | How else would you have a static parser handle these two
         | builtins? They are in a bit of an awkward middle ground between
         | builtin and keyword. My instinct is that giving them special
         | treatment in the parser to allow tokens like `(`, while at the
         | same time representing them in the syntax tree with opaque
         | strings as expressions, would be pretty underwhelming to any
         | users of the parser.
         | 
         | That said, we already have that problem with `let "foo=123"`
         | for example, where our parser currently represents the
         | expression as the quoted string without going any deeper.
         | https://github.com/mvdan/sh/issues/754#issuecomment-96329574...
         | considers doing a second parse stage in the shell interpreter
         | to fix cases like these, though always doing a second parse
         | could get expensive.
         | 
         | We _could_ leave all arithmetic expressions as input strings in
         | the parser, and do all the actual parsing when they are
         | evaluated. That would be more compatible with Bash and more
         | consistent. But it would also be less useful to any parser
         | users who don't run into any of these weird edge cases, which
         | aren't common at all, I think.
         | 
         | In short, I have some ideas, but I'm not sure at all what's
         | best :) Doing a good job for 99% of users feels better than
         | aiming for 100% compatibility with bash syntax, particularly
         | where bash syntax is a bit weird.
        
           | auveair wrote:
           | Thank you for taking the time to answer, as a random user it
           | was illuminating.
        
       | jmholla wrote:
       | Anybody have any luck building the image? It fails for me on
       | podman and docker.
        
       | ufo wrote:
       | Are there examples of what the formatted code looks like?
        
         | usr1106 wrote:
         | We introduced it at work after the code base containing had
         | been developed for 3 - 4 years with just manual reviews. The
         | changes we needed to make were rather small and most of them
         | were oversights, the code should not have looked like that in
         | the first place. Of course your mileage might vary.
         | 
         | The only thing that disturbed me personally is no space before
         | semicolon. Without having read what spec says I think the
         | semicolon in shell is more of a command separator than a
         | terminator. So I had always formatted it symmetrically, with
         | space before and after like e.g. && or a pipe. shfmt did not
         | support that so I had to adapt. Still having a tool and
         | skipping review discussions outweighs this minor matter of
         | taste.
        
           | erik_seaberg wrote:
           | I try to use line breaks instead, it only took a little
           | getting used to                 for i in $(seq 100)       do
           | if expr $i % 5 > /dev/null          then if expr $i % 3 >
           | /dev/null               then echo $i               else echo
           | fizz               fi          else if expr $i % 3 >
           | /dev/null               then echo buzz               else
           | echo fizzbuzz               fi          fi       done
        
             | usr1106 wrote:
             | I did that at university around 30 years ago. I think
             | nowadays 1TBS is much more common.
        
               | erik_seaberg wrote:
               | Yeah, I use 1TBS and cuddled elses in Scala/Java/C++, but
               | adding a semicolon to do it with a keyword feels like
               | arguing with the grammar.
        
         | mvdan wrote:
         | https://github.com/mvdan/sh/blob/master/syntax/canonical.sh is
         | one small example.
        
       | oweiler wrote:
       | I've used it on a small project and it worked beautifully. It
       | even understands and respects Bats syntax.
        
       | jesusofnazarath wrote:
       | [dead]
        
       | [deleted]
        
       | eschneider wrote:
       | Oooh, this looks fun.
        
       | jeremy_wiebe wrote:
       | And if you use fish, it comes with a built-in formatting
       | function.
       | 
       | https://fishshell.com/docs/current/cmds/fish_indent.html
        
       ___________________________________________________________________
       (page generated 2023-02-11 23:01 UTC)