TE
TechEcho
Home24h TopNewestBestAskShowJobs
GitHubTwitter
Home

TechEcho

A tech news platform built with Next.js, providing global tech news and discussions.

GitHubTwitter

Home

HomeNewestBestAskShowJobs

Resources

HackerNews APIOriginal HackerNewsNext.js

© 2025 TechEcho. All rights reserved.

Jo – a shell command to create JSON (2016)

325 pointsby robfigover 3 years ago

22 comments

EdSchoutenover 3 years ago
I remember that when I worked at Google about a decade ago, there was this common saying:<p>&quot;If the first version of your shell script is more than five lines long, you should have written it in Python.&quot;<p>I think there&#x27;s a lot of truth in that. None of the examples presented in the article look better than had they been written in some existing scripting&#x2F;programming language. In fact, had they been written in Python or Javascript, it would have been far more obvious what the resulting output would have been, considering that those languages already use {} for objects and [] for lists.<p>For example, take this example:<p><pre><code> jo -p name=JP object=$(jo fruit=Orange point=$(jo x=10 y=20) number=17) sunday=false </code></pre> In Python you would write it like this:<p><pre><code> json.dumps({&quot;name&quot;: &quot;JP&quot;, &quot;object&quot;: {&quot;fruit&quot;: &quot;Orange&quot;, &quot;point&quot;: {&quot;x&quot;: 10, &quot;y&quot;: 20}, &quot;number&quot;: 17}, &quot;sunday&quot;: False}) </code></pre> Only a bit more code, but at least it won&#x27;t suffer from the Norway problem. Even though Python isn&#x27;t the fastest language out there, it&#x27;s likely still faster than the shell command above. There is no need to construct a fork bomb just to generate some JSON.
评论 #30226312 未加载
评论 #30231008 未加载
评论 #30228727 未加载
评论 #30229491 未加载
评论 #30229463 未加载
评论 #30229033 未加载
评论 #30227103 未加载
评论 #30228601 未加载
评论 #30227955 未加载
评论 #30230403 未加载
评论 #30226302 未加载
评论 #30227093 未加载
评论 #30227323 未加载
评论 #30226259 未加载
评论 #30226934 未加载
评论 #30228109 未加载
seletskiyover 3 years ago
Some time ago I wrote zsh helper [1] that uses jo to quickly construct complex JSON requests, mainly for testing and quering services from console.<p>Paired with httpie [2] aliases [3] it produces concise APL-like syntax:<p><pre><code> POST https:&#x2F;&#x2F;httpbin.org&#x2F;post test:=j`a=b c=`e=3` l=`*1 2 3`` </code></pre> Which translates to:<p><pre><code> http POST https:&#x2F;&#x2F;httpbin.org&#x2F;post test:=&quot;$(jo a=b c=&quot;$(jo e=3)&quot; l=&quot;$(jo -a 1 2 3)&quot;)&quot; </code></pre> Or, in other words, sending POST with the following body:<p><pre><code> {&quot;a&quot;:&quot;b&quot;,&quot;c&quot;:{&quot;e&quot;:3},&quot;l&quot;:[1,2,3]} </code></pre> [1]: <a href="https:&#x2F;&#x2F;github.com&#x2F;seletskiy&#x2F;dotfiles&#x2F;blob&#x2F;78ac45c01bdf019aec6182668e7b571ab4419b6b&#x2F;.zshrc#L479-L482" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;seletskiy&#x2F;dotfiles&#x2F;blob&#x2F;78ac45c01bdf019ae...</a> [2]: <a href="https:&#x2F;&#x2F;httpie.io&#x2F;" rel="nofollow">https:&#x2F;&#x2F;httpie.io&#x2F;</a> [3]: <a href="https:&#x2F;&#x2F;github.com&#x2F;seletskiy&#x2F;dotfiles&#x2F;blob&#x2F;78ac45c01bdf019aec6182668e7b571ab4419b6b&#x2F;.zshrc#L821-L828" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;seletskiy&#x2F;dotfiles&#x2F;blob&#x2F;78ac45c01bdf019ae...</a>
评论 #30225405 未加载
matjaover 3 years ago
I like it, very concise but retains all the features you need.<p>`jq` can construct JSON &quot;safely&quot; from shell constructs, but is rather more verbose - e.g. with the same examples:<p><pre><code> $ jq -n --arg name Jane &#x27;{&quot;name&quot;:$name}&#x27; $ jq -n \ --argjson time $(date +%s) \ --arg dir $HOME \ &#x27;{&quot;time&quot;:$time,&quot;dir&quot;:$dir}&#x27; $ jq -n &#x27;$ARGS.positional&#x27; --args spring summer winter $ jq -n \ --arg name JP \ --argjson object &quot;$( jq -n \ --arg fruit Orange \ --argjson point &quot;$( jq -n \ --argjson x 10 \ --argjson y 20 \ &#x27;{&quot;x&quot;:$x,&quot;y&quot;:$y}&#x27; \ )&quot; \ --argjson number 17 \ &#x27;{&quot;fruit&quot;:$fruit,&quot;point&quot;:$point,&quot;number&quot;:$number}&#x27; \ )&quot; \ --argjson sunday false \ &#x27;{&quot;name&quot;:$name,&quot;object&quot;:$object,&quot;sunday&quot;:$sunday}&#x27;</code></pre>
pydryover 3 years ago
&gt;Bam! Jo tries to be clever about types and knows null, booleans, strings and numbers.<p>I&#x27;m very skeptical of this. If I put x=001979 in as a value I dont think I want you trying to guess if that&#x27;s supposed to be an integer or a string.<p>This sounds like the Norway Problem waiting to happen.
评论 #30226534 未加载
评论 #30225908 未加载
评论 #30225848 未加载
评论 #30225888 未加载
fooycover 3 years ago
<p><pre><code> &gt; jo normally treats value as a literal string value, unless it begins with one of the following characters: &gt; value action &gt; @file substitute the contents of file as-is &gt; %file substitute the contents of file in base64-encoded form &gt; :file interpret the contents of file as JSON, and substitute the result </code></pre> This is convenient but also very dangerous. This feature will cause the content of an arbitrary file to be embed in the JSON if any value starts with a `@`, `%`, or `:`.<p>This will be a source of bugs or security issues for any script generating json with dynamic values.
kazinatorover 3 years ago
Five minute job:<p><pre><code> $ .&#x2F;jo foo=1 bar=2 obj=$(.&#x2F;jo -a 1 2 3 &quot;&lt;&#x2F;script&quot; &#x27;&quot;&#x27;) {&quot;foo&quot;:1,&quot;obj&quot;:[1,2,3,&quot;&lt;\&#x2F;script&quot;,&quot;\&quot;&quot;],&quot;bar&quot;:2} $ .&#x2F;jo foo=&#x27;abc &gt; def &gt; ghi&#x27; {&quot;foo&quot;:&quot;abc\ndef\nghi&quot;} $ cat jo #!&#x2F;usr&#x2F;local&#x2F;bin&#x2F;txr --lisp (define-option-struct jo-opts nil (a array :bool &quot;Produce array instead of object&quot;) (nil help :bool &quot;Print this help&quot;)) (defvarl jo-name *load-path*) (defun json-val (str) (match-case str (&quot;true&quot; t) (&quot;false&quot; nil) (&quot;null&quot; &#x27;null) (`{@nil` (get-json str)) (`[@nil` (get-json str)) (@else (iflet ((num (tofloat else))) num else)))) (let ((o (new jo-opts))) o.(getopts *args*) (when o.help (put-line &quot;Usage:\n&quot;) (put-line ` @{jo-name} [options] arg*`) o.(opthelp) (exit 0)) (if o.array (let ((items [mapcar json-val o.out-args])) (put-jsonl (vec-list items))) (let ((pairs [mapcar (lambda (:match) ((`@this=@that`) (list (json-val this) (json-val that))) ((@else) (error &quot;~a: arguments must be name=obj pairs&quot; jo-name))) o.out-args])) (put-jsonl ^#H(() ,*pairs)))))</code></pre>
评论 #30233988 未加载
montroserover 3 years ago
This is cool.<p>In the spirit of &quot;do one thing well&quot;, I&#x27;d so rather use this to construct JSON payloads to curl requests than the curl project&#x27;s own &quot;json part&quot; proposal[1] under consideration.<p>[1]: <a href="https:&#x2F;&#x2F;github.com&#x2F;curl&#x2F;curl&#x2F;wiki&#x2F;JSON#--jp-part" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;curl&#x2F;curl&#x2F;wiki&#x2F;JSON#--jp-part</a>
评论 #30225792 未加载
lordleftover 3 years ago
The more I work with JSON, the more I crave some kind of dedicated json editor to easily visualize and manipulate json objects, and to serialize &#x2F; deserialize strings. This is especially the case with truly massive JSON objects with multiple layers of nesting. Anyway, cool tool that makes one part of the process of whipping up JSON a little less painful
评论 #30225384 未加载
评论 #30225529 未加载
评论 #30226104 未加载
videogreg93over 3 years ago
Looks neat, but the documentation was hard to follow. A lot of typos, and some things didn&#x27;t make sense. For example, I think 2 paragraphs were swapped because the example code below the paragraph taking about using square brackets has no square brackets (but nested objects) while the paragraph right after talks about nested objects but it&#x27;s example doesn&#x27;t show it (it does however seemingly demonstrate the square bracket feature mentioned previously)
ysk73over 3 years ago
And I just use Nushell. You have built-ins to create (and parse) not only json but also url, xml and more... <a href="https:&#x2F;&#x2F;github.com&#x2F;skelly37&#x2F;Reject-POSUCKS-embrace-Nushell#built-in-parsers" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;skelly37&#x2F;Reject-POSUCKS-embrace-Nushell#b...</a>
hyperpallium2over 3 years ago
This looks like an informally specified shell-friendly alternative json syntax.<p>I wonder if a formal syntax would help? Perhaps including relevant shell syntax (interpolation, subshell). It could clarify issues, and this different perspective might suggest improvements or different approaches.
mbrockover 3 years ago
There&#x27;s also jshon which is a simple stack-based DSL for constructing JSON from shell scripts.<p><a href="http:&#x2F;&#x2F;kmkeen.com&#x2F;jshon&#x2F;" rel="nofollow">http:&#x2F;&#x2F;kmkeen.com&#x2F;jshon&#x2F;</a><p>It&#x27;s written in C and is not actively developed. The latest commit, it seems, was a pull request from me back in 2018 that fixed a null-termination issue that led to memory corruption.<p>Because I couldn&#x27;t rely on jshon being correct, I rewrote it in Haskell here:<p><a href="https:&#x2F;&#x2F;github.com&#x2F;dapphub&#x2F;dapptools&#x2F;tree&#x2F;master&#x2F;src&#x2F;jays" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;dapphub&#x2F;dapptools&#x2F;tree&#x2F;master&#x2F;src&#x2F;jays</a><p>This is also not developed actively but it&#x27;s a single simple ~200 line Haskell program.
johncsover 3 years ago
In the common case where you trust your input entirely you can just interpret your string as JavaScript. Then you don&#x27;t even need to use quotes for the key names.<p><pre><code> $ alias fooson=&quot;node --eval \&quot;console.log(JSON.stringify(eval(&#x27;(&#x27; + process.argv[1] + &#x27;)&#x27;)))\&quot;&quot; $ fooson &quot;{time: $(date +%s), dir: &#x27;$HOME&#x27;}&quot; {&quot;time&quot;:1457195712,&quot;dir&quot;:&quot;&#x2F;Users&#x2F;jpm&quot;} </code></pre> It may be a bit nicer to place that JavaScript in your path as a node script instead of using an alias.<p><pre><code> #!&#x2F;usr&#x2F;bin&#x2F;env node console.log(JSON.stringify(eval(&#x27;(&#x27; + process.argv[2] + &#x27;)&#x27;))) </code></pre> Since fooson&#x27;s argument is being interpreted as JavaScript, you can access your environment through process.env. But you could make a slightly easier syntax in various ways. Like with this script:<p><pre><code> #!&#x2F;usr&#x2F;bin&#x2F;env node for(const [k, v] of Object.entries(process.env)) { if (!global.hasOwnProperty(k)) { global[k] = v; } } console.log(JSON.stringify(eval(&#x27;(&#x27; + process.argv[2] + &#x27;)&#x27;))) </code></pre> Now environmental variables can be access as if they were JS variables. This can let you handle strings with annoying quoting.<p><pre><code> $ export BAR=&quot;\&quot;&#x27;&#x27;&#x27;\&quot;\&quot;&quot; $ fooson &#x27;{bar: BAR}&#x27; {&quot;bar&quot;: &quot;\&quot;&#x27;&#x27;&#x27;\&quot;\&quot;&quot;} </code></pre> If you wanted to do this without trusting your input so much, a JSON dialect where you can use single-quoted strings would get you pretty far.<p><pre><code> $ fooson &quot;{&#x27;time&#x27;: $(date +%s), &#x27;dir&#x27;: &#x27;$HOME&#x27;}&quot; {&quot;time&quot;:1457195712,&quot;dir&quot;:&quot;&#x2F;Users&#x2F;jpm&quot;} </code></pre> If you taught the utility to expand env variables itself you&#x27;d be able to handle strings with mixed quoting as well.<p><pre><code> $ export BAR=&quot;\&quot;&#x27;&#x27;&#x27;\&quot;\&quot;&quot; $ fooson &#x27;{&quot;bar&quot;: &quot;$BAR&quot;}&#x27; {&quot;bar&quot;: &quot;\&quot;&#x27;&#x27;&#x27;\&quot;\&quot;&quot;} </code></pre> You&#x27;d only need small modifications to a JSON parser to make this work.
评论 #30232087 未加载
pwdisswordfish9over 3 years ago
Does it suffer from the Norway problem?
评论 #30228343 未加载
评论 #30225584 未加载
ilyashover 3 years ago
Depending on your exact needs, you might also want to try Next Generation Shell. It&#x27;s a fully featured programming language for the DevOps-y stuff with convenient &quot;print JSON&quot; switch so &quot;ngs -pj YOUR_EXPR&quot; evaluates the expression, serializes the result as JSON and prints it.<p>Disclosure: I&#x27;m the author<p>Project link: <a href="https:&#x2F;&#x2F;github.com&#x2F;ngs-lang&#x2F;ngs" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;ngs-lang&#x2F;ngs</a><p>Enjoy!
Shadonototraover 3 years ago
Dang yo, why it&#x27;s not &quot; Jo – a shell command to create JSON written in C (2016) (jpmens.net)&quot;<p>You guys do that for &quot;written in Rust&quot;
评论 #30232941 未加载
tedmistonover 3 years ago
Direct link to repo:<p><a href="https:&#x2F;&#x2F;github.com&#x2F;jpmens&#x2F;jo" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;jpmens&#x2F;jo</a>
visargaover 3 years ago
You can implement this and many other single purpose CLI tools with inline Python or Perl or other language. Easier to remember because it&#x27;s your favorite language.<p><pre><code> python -c &quot;import json; print(json.dumps(dict(a=10, b=False)))&quot;</code></pre>
评论 #30229897 未加载
nikolayover 3 years ago
I&#x27;ve been using it for years and it&#x27;s a great companion of jq and jp (JMESPath).
borgchickover 3 years ago
Awesome, thank you. Lovely counterpart to jq :)
higginsover 3 years ago
next to &quot;copy as cURL&quot; in dev tools, this might make the regular rotation
mirekrusinover 3 years ago
Could be simply called `json`.
评论 #30225483 未加载