Hacker News new | past | comments | ask | show | jobs | submit login

This is incredibly high-quality BASH programming, as a fellow bash freak I am studying this code, and even I am learning some new techniques.

https://github.com/h4l/json.bash/blob/main/json.bash

You've boiled it down to a set of very elegant constructs. Respect. Thank you @h4l, this is badass.

I hope you follow up with a golang or rust implementation, that would really be something else.

p.s. I noticed the following odd behaviors with escaping delimiters (e.g. "="), is there a way to get an un-escaped equal sign as the trailing part of a key or leading part of a value?

  $ docker container run --rm ghcr.io/h4l/json.bash/jb msg=Hi
  {"msg":"Hi"}
  $ docker container run --rm ghcr.io/h4l/json.bash/jb msg=\=Hi
  {"msg=Hi":"msg=Hi"}
  $ docker container run --rm ghcr.io/h4l/json.bash/jb "msg=\=Hi"
  {"msg":"\\=Hi"}
  $ docker container run --rm ghcr.io/h4l/json.bash/jb "msg\==\=Hi"
  {"msg\\=\\":"Hi"}
  $ docker container run --rm ghcr.io/h4l/json.bash/jb "msg\\==\=Hi"
  {"msg\\=\\":"Hi"}
  $ docker container run --rm ghcr.io/h4l/json.bash/jb "msg\\===Hi"
  {"msg\\=":"Hi"}





Thank you, that's high praise! I learnt a lot about bash writing this, but I've also not looked at the code in a few months, and it's already starting to look quite intimidating!

I definitely like the idea of a goland/rust implementation, there are certainly things I could improve.

So the argument syntax escapes by repeating a character rather than backslash. I chose this because with backslashes escapes it would be unclear whether a backslash was in the shell syntax or the jb syntax, and users may end up needing to double escape backslashes, which is no fun! Whereas a shell will always ignore two copies of a character like =:@.

The downside of double-escaping is that the syntax can be ambiguous, so sometimes you need to include the middle type marker to disambiguate the key from the value. But the type can be empty, so just : works:

    $ jb ===msg==:==hi=
    {"=msg=":"=hi="}
In the key part, the first = begins the key, the == following are an escaped =. The first = following the : marks the value, and everything after is not parsed, so =hi= is literal.

When you have reserved characters in keys/values (especially if they're dynamic), it's easiest to store the values in variables and reference them with @var syntax:

    $ k='=msg=' v='=hi=' jb @k@v
    {"=msg=":"=hi="}

How is this different to this https://github.com/kellyjonbrazil/jc

jc has many parsers for the specific output format of various programs, it can automatically create a JSON object structure using its knowledge of each format.

jb doesn't have high-level knowledge of other formats, it can read from common shell data sources, like command-line arguments, environment variables and files. It gives you ways to pull several of these sources into a single JSON object.

jb understands some simple/general formats commonly used in shell environments:

- key=value pairs (e.g. environment variable declarations, like the `env` program prints

- delimited lists, like a,b,c,d; (but any character can be the delimiter) including null-delimited (commonly used to separate lists of file paths)

- JSON itself — jb can validate and merge together arrays and objects

You can use these simple sources to build up a more complex structure, e.g. using a pipeline of other command line tools to generate null-delimited data, or envar declarations, then consuming the program's output via process substitution <(...). (See the section in the README that explains process substitution if you're not familiar, it's really powerful.)

So jb is more suited to creating ad-hoc JSON for specific tasks. If you had both jc and jb available and jc could read the source you need, you'd prefer jc.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: