jqが使えなくても大丈夫なJavaScriptシェル芸

jqが使えなくても大丈夫なJavaScriptシェル芸:

jqをインストールできなかったり、jqで複雑な加工をさせたいが構文が難しくて覚えられなかったりと、

なんらかの事情でjqを使わずjavascript(Node.js)でJSONを処理したいことが稀にあるかもしれません。

Node.jsは標準入力に弱い?そんな事はありません。ワンライナーで処理できます!


JSONファイルが小さいとき

下記のようなJSONを想定します。1

sample.json
{ 
  "menu": { 
  "id": "file", 
    "value": "File", 
    "popup": { 
      "menuitem": [ 
      {"value": "New", "onclick": "CreateNewDoc()"}, 
      {"value": "Open", "onclick": "OpenDoc()"}, 
      {"value": "Close", "onclick": "CloseDoc()"} 
      ] 
    } 
  } 
} 
ワンライナーで処理します。

$ cat sample.json | xargs -0 -i node -pe '({})' 
{ menu: 
   { id: 'file', 
     value: 'File', 
     popup: 
      { menuitem: 
         [ { value: 'New', onclick: 'CreateNewDoc()' }, 
           { value: 'Open', onclick: 'OpenDoc()' }, 
           { value: 'Close', onclick: 'CloseDoc()' } ] } } } 
 
## 少しフィルタしてみる 
$ cat sample.json | xargs -0 -i node -pe '({}).menu.popup.menuitem.map(_=>_.value)' 
[ 'New', 'Open', 'Close' ] 
簡単ですね。

しかし、この方法だと実は限界があり、

シェルが展開した文字列が OSの制限 (正確には execve(2) の制限) を越えると動かなくなります。2

sample.big.json
{ docs: 
   [ { "_id": "14cd7192b2d699a606bde01c3123c750" }, 
     { "_id": "14cd7192b2d699a606bde01c3123d685" }, 
     { "_id": "14cd7192b2d699a606bde01c3123ddd4" }, 
     { "_id": "14cd7192b2d699a606bde01c3123f441" }, 
     { "_id": "14cd7192b2d699a606bde01c3123f6df" }, 
     { "_id": "14cd7192b2d699a606bde01c31240655" }, 
     { "_id": "14cd7192b2d699a606bde01c31241075" }, 
     { "_id": "14cd7192b2d699a606bde01c31241d31" }, 
     { "_id": "14cd7192b2d699a606bde01c31242a44" },  
     // 省略 
    ] 
 } 
## ファイルサイズ(byte) 
$ cat sample.big.json | wc  -c 
69656 
 
$ cat sample.big.json | xargs -0 -i node -pe '({})' 
xargs: argument line too long 
OSの最大値は下記で確認できます。

$ getconf ARG_MAX 
32000 
Git Bash上で実行すると32KBくらいまでみたいです。

ちなみにGCPのCloud Shellだと2MB(2097152byte)でしたので、Git bash相当小さいような。。。


JSONファイルが大きいとき

OSの制限にかからないワンライナーにします。

$ cat <(sed '1s/^/_=/' sample.big.json) <(echo _) | node -p - 
 
{ docs: 
   [ { _id: '14cd7192b2d699a606bde01c3123c750' }, 
     { _id: '14cd7192b2d699a606bde01c3123d685' }, 
     { _id: '14cd7192b2d699a606bde01c3123ddd4' }, 
     { _id: '14cd7192b2d699a606bde01c3123f441' }, 
     { _id: '14cd7192b2d699a606bde01c3123f6df' }, 
     ... 791 more items ] 
 } 
 
## すこしフィルタしてみる 
$ cat <(sed '1s/^/_=/' sample.big.json) <(echo '_.docs.slice(0,3).map(v=>v._id)') | node -p - 
[ '14cd7192b2d699a606bde01c3123c750', 
  '14cd7192b2d699a606bde01c3123d685', 
  '14cd7192b2d699a606bde01c3123ddd4' ] 


jqのようにきれいに整形

上の方法だと短いですが、

ダブルコーテーションが外れ、

すこしインデントが微妙になり、

大きなリストは「... xxx more items」のように省略されてしまうので、

きれいに出力するようにします。。。

$ cat <(sed '1s/^/_=/' sample.big.json) <(echo 'JSON.stringify(_,null,"\t")') | node -p - 
{ 
        "docs": [ 
                { 
                        "_id": "14cd7192b2d699a606bde01c3123c750" 
                }, 
                { 
                        "_id": "14cd7192b2d699a606bde01c3123d685" 
                }, 
                { 
                        "_id": "14cd7192b2d699a606bde01c3123ddd4" 
                }, 
                { 
                        "_id": "14cd7192b2d699a606bde01c3123f441" 
                }, 
                { 
                        "_id": "14cd7192b2d699a606bde01c3123f6df" 
                }, 
                { 
                        "_id": "14cd7192b2d699a606bde01c31240655" 
                }, 
        //省略しますが全部出力されます 
        ] 
} 
 
## 少しフィルタしてみる 
$ cat <(sed '1s/^/_=/' sample.big.json) <(echo 'JSON.stringify(_.docs.slice(0,3).map(v=>v._id),null,"\t")') | node -p - 
[ 
        "14cd7192b2d699a606bde01c3123c750", 
        "14cd7192b2d699a606bde01c3123d685", 
        "14cd7192b2d699a606bde01c3123ddd4" 
] 
ここまで来るとjq使ったほうが早そうな気……これでNode.jsさえあればjq使わなくても大丈夫ですし、

複雑な加工でも学習コスト0で気軽にJSONを加工できるようになりますね!

他に良い方法があればコメントお願いします。


備考

$ cat sample.big.json | jq [.docs[0:3][]._id] 
[ 
  "14cd7192b2d699a606bde01c3123c750", 
  "14cd7192b2d699a606bde01c3123d685", 
  "14cd7192b2d699a606bde01c3123ddd4" 
] 

コメント

このブログの人気の投稿

投稿時間:2021-06-20 02:06:12 RSSフィード2021-06-20 02:00 分まとめ(3871件)

投稿時間:2021-04-30 23:37:32 RSSフィード2021-04-30 23:00 分まとめ(42件)

投稿時間:2023-02-05 02:09:04 RSSフィード2023-02-05 02:00 分まとめ(9件)