話題のjoを試してみた

コマンドラインから簡単にJSON形式のテキストを作成できるという[jo](https://github.com/jpmens/jo)を試してみました。

![jo](https://qiita-image-store.s3.amazonaws.com/0/39027/bd216430-af9f-44af-d457-740d5592c5c8.png)
[jpmens/jo: JSON output from a shell](https://github.com/jpmens/jo)

## インストール

インストール方法はいくつかあるようですが、git cloneでソースからコンパイルする方法でインストールを行いました。

```bash:
$ git clone git://github.com/jpmens/jo.git
$ cd jo
$ autoreconf -i # autoconfパッケージに含まれています
$ ./configure
$ make
$ sudo make install
```

※ autoreconfコマンドがインストールされていない場合は、下記パッケージをインストールしておきます。

```bash:
$ sudo yum install autoconf -y
$ sudo yum install automake -y
```

無事にインストールが完了すると、joコマンドとマニュアルがインストールされます。

```bash:
$ which jo
/usr/local/bin/jo
$ man jo
```

## joコマンドの使い方

joのコマンド引数に`key=value`を指定すると、JSONオブジェクトを作成できます。

```
$ jo key=value
{"key":"value"}
```

```
$ jo name=jo version=0.7
{"name":"jo","version":0.7}
```

`-p`オプションを指定すると見やすい形式に整形されて出力されます。

```
$ jo name=jo version=0.7 -p
{
   "name": "jo",
   "version": 0.7
}
```

配列を作りたい場合は`-a`オプションを指定します。

```
$ jo A B C -a
["A","B","C"]
```

BOOL値を作りたい場合は、`=`の代わりに`@`を使います。

```
$ jo hungry@1
{"hungry":true}
```

以下の値はtrueとなり、それ以外はfalseとなります。

* 0以外の数字
* `T`または`t`で始まる文字

```
$ jo a@T b@true c@1 A@F B@false C@0 -p
{
   "a": true,
   "b": true,
   "c": true,
   "A": false,
   "B": false,
   "C": false
}
```

null値を作りたい場合は、`=`または`@`に続く文字を空にします。

```
$ jo name=
{"name":null}
$ jo name@
{"name":null}
```


要素をネストしたい場合は、`jo`コマンドを組み合わせます。

```
$ jo key1=value1 obj=$(jo key2=value2) -p
{
   "key1": "value1",
   "obj": {
      "key2": "value2"
   }
}
```

※上記ではネストする要素の作成に`$(コマンド)`を使いましたが、`` `コマンド` ``でも結果は同じです。

```
$ jo key1=value1 obj=`jo key2=value2` -p
{
   "key1": "value1",
   "obj": {
      "key2": "value2"
   }
}
```

`[]`を使い配列やオブジェクトを作成する方法もあります。

```
$ jo num[]=1 num[]=2 geo[lat]=123 geo[lon]=456 -p
{
   "num": [
      1,
      2
   ],
   "geo": {
      "lat": 123,
      "lon": 456
   }
}
```

数値を文字列にしたい場合は、エスケープしたダブルクォーテーションで数値を囲みます。

```
$ jo num=\"123\"
{"num":"123"}
```

標準入力からデータを受け取ることも出来ます。

```
$ seq 1 5 | jo -a
[1,2,3,4,5]
```

※2016-03-16追記
jo v1.0がリリースされていました。
ファイルの内容の展開や、BASE64エンコードが出来るようになったようです。

ファイルの内容をBASE64エンコードする場合は、ファイル名の前に``%``をつけます。

```
$ jo image=%image.png -p
{
   "image": "44GN44GV44G+Ieimi+OBpuOBhOOCi+OBquODgyEK44GN44GV44G+Ieimi+OBpuOBhOOCi+OBquODgyEK44GN44GV44G+Ieimi+OBpuOBhOOCi+OBquODgyEK"
}
```

ファイル名の前に``@``をつけると、ファイルの内容をそのまま展開します。

```
$ jo authors=@AUTHORS -p
{
   "authors": "Jan-Piet Mens <jpmens@gmail.com>"
}
```

## 応用

カレントディレクトリのファイル一覧をJSON配列にする。

```
$ jo * -ap
[
   "AUTHORS",
   "COPYING",
   "ChangeLog",
   "INSTALL",
   "Makefile",
   "Makefile.am",
   "Makefile.in",
   "NEWS",
   "README",
   "README.md",
   "aclocal.m4",
   "autom4te.cache",
   "config.log",
   "config.status",
   "configure",
   "configure.ac",
   "depcomp",
   "install-sh",
   "jo",
   "jo-logo.png",
   "jo.1",
   "jo.c",
   "jo.md",
   "jo.o",
   "jo.pandoc",
   "json.c",
   "json.h",
   "json.o",
   "missing",
   "test-driver",
   "tests.sh"
]
```

composer.jsonを作る。

```
$ jo require=$(jo phpunit/phpunit=4.8.\*) -p > composer.json
$ more composer.json
{
   "require": {
      "phpunit/phpunit": "4.8.*"
   }
}
```

環境変数をJSON化する。

```
$ env | jo -p
{
   ...略...
   "SHELL": "/bin/bash",
   "SSH_TTY": "/dev/pts/0",
   "LANG": "ja_JP.UTF-8",
   "_": "/bin/env"
   ...略...
}
```

`key=value`形式の設定ファイルをJSON化する。

```
$ cat /etc/sysconfig/network-scripts/ifcfg-eth0 
DEVICE=eth0
BOOTPROTO=dhcp
ONBOOT=yes
TYPE=Ethernet
USERCTL=yes
PEERDNS=yes
IPV6INIT=no
PERSISTENT_DHCLIENT=yes

$ jo < /etc/sysconfig/network-scripts/ifcfg-eth0 -p
{
   "DEVICE": "eth0",
   "BOOTPROTO": "dhcp",
   "ONBOOT": "yes",
   "TYPE": "Ethernet",
   "USERCTL": "yes",
   "PEERDNS": "yes",
   "IPV6INIT": "no",
   "PERSISTENT_DHCLIENT": "yes"
}
```

100までの素数をJSON化する。

```
$ jo prime_number=$(seq 2 100 | factor | awk 'NF==2 {print $2}' | jo -a)
{"prime_number":[2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97]}
```

自分が何者であるかをJSON化する。

```
$ jo name=$(whoami)
{"name":"hoge"}
```

## joを使ってみた感想

便利そうなコマンドではありますが、今のところ、うまい活用法がみつかりませんでした…