name: centering layout: true class: center, middle --- name: coverpage # シェル芸で使いたい
jqイディオム Masayoshi Nomura / @nmrmsys 2016/04/30 第22回 シェル芸勉強会 大阪サテライト --- layout: false ## 自己紹介 .introduce-left[ ### ■ なまえ: 野村 昌由 ### ■ 業務システム開発
とインフラ業 ### ■ .NETerだけど最近はAWSばっか
過去は閉鎖環境でツール作成など
シェル芸は実用主義派、Ansible
Redmineなどにも興味あり〼 ### ■ 所属してる会社が絶賛人手不足
iOS・業務・インフラ・ハード・
その他変態エンジニヤーの方々
お助け下さい! ] .introduce-right[ .center[ ![avator](img/avator.png) ### @nmrmsys ] ] ??? 本名のローマ字綴りを子音だけにしたもの、アバターは Tim O'Reillyさん Web2.0 --- ## 会社紹介 [![product](img/product_newer.png)](http://www.asx.co.jp/) 事業所は、新大阪、新橋、大連にあります。 --- # jqとは? ### 説明しよう、コマンドラインのJSON処理装置である。
入力として受け取ったJSONデータにフィルタを
適用することで、結果のJSONデータを出力する
コマンドラインツールのフィルタプログラムである。 # なぜjqか? ### jsawkや jo, jsonなど、JSONを処理するツールは
他にもいろいろあるけど、出来る事の広さはjqが
やはり他の追随を許さない、取っ付きづらいけど
まあ覚えるしか無い、でやってみたら奥が深イイ
これ正規表現とか、sed, awkとおんなじ奴やで! --- ### 定番のヘルプ表示 ```xml $ jq -h jq - commandline JSON processor [version 1.5] Usage: jq [options]
[file...] jq is a tool for processing JSON inputs, applying the given filter to its JSON text inputs and producing the filter's results as JSON on standard output. The simplest filter is ., which is the identity filter, copying jq's input to its output unmodified (except for formatting). For more advanced filters see the jq(1) manpage ("man jq") and/or https://stedolan.github.io/jq Some of the options include: -c compact instead of pretty-printed output; -n use `null` as the single input value; -e set the exit status code based on the output; -s read (slurp) all inputs into an array; apply filter to it; -r output raw strings, not JSON texts; -R read raw strings, not JSON texts; -C colorize JSON; -M monochrome (don't colorize JSON); -S sort keys of objects on output; --tab use tabs for indentation; --arg a v set variable $a to value
; --argjson a v set variable $a to JSON value
; --slurpfile a f set variable $a to an array of JSON texts read from
; See the manpage for more options. ``` --- ## カラー表示にする起動オプション ``` $ aws ec2 describe-instances | jq -C '.' | less -R ``` #### プロファイルで alias jqc='jq -C' とか export LESS='-R' しておくと良いかも ## JSONの抽出 ``` $ aws ec2 describe-instances | jq '.' ``` ``` $ aws ec2 describe-instances | jq '.Reservations' ``` ``` $ aws ec2 describe-instances | jq '.Reservations[]' ``` ``` $ aws ec2 describe-instances | jq '.Reservations[].Instances[]' ``` #### . は入力内容そのものを表すフィルタ、jq界隈ではセレクタではなくフィルタという #### [n] や [m,n] など [l:n] で配列の要素取得、[]は特殊で配列の中身を取り出す --- ## JSONの再構築 ``` $ 省略 | jq '.Reservations[].Instances[] | .InstanceId' ``` ``` $ 省略 | jq '省略 | [ .InstanceId, .InstanceType, .State.Name ]' ``` ``` $ 省略 | jq '省略 | { InstanceId: .InstanceId, InstanceType: .InstanceType }' ``` ``` $ 省略 | jq '省略 | { InstanceId, InstanceType }' #上記の短縮形 ``` ## 結果の確認方法 ``` $ aws ec2 describe-instances | jq '.Reservations | type' ``` ``` $ aws ec2 describe-instances | jq '.Reservations | length' ``` ``` $ aws ec2 describe-instances | jq '.Reservations | keys' ``` #### これを見ると jqのフィルタの | がオブジェクトパイプラインなのだと分かります。 --- ## JSONの抽出2 ``` $ 省略 | jq '.Reservations[].Instances[] | [ .InstanceId, .Tags[]? ]' ``` ``` $ 省略 | jq '省略 | [ .InstanceId, (.Tags[]? | select(.Key == "Name")) ]' ``` ``` $ 省略 | jq '省略 | [ .InstanceId, (.Tags[]? | select(.Key == "Name")).Value ]' ``` #### key/value用に from_entries関数があるが、要素が抜けるとエラーになるので。。。 ## 結果の整形 ``` $ 省略 | jq -c '省略 | [ .InstanceId, .InstanceType, .State.Name ]' ``` ``` $ 省略 | jq -r '省略 | [ .InstanceId, .InstanceType, .State.Name ] | @csv' ``` ``` $ 省略 | jq -r '省略 | [ .InstanceId, .InstanceType, .State.Name ] | @tsv' ``` ``` $ 省略 | jq -r '省略 | [ .InstanceId, .InstanceType, .State.Name ] | @sh' ``` ??? -c --compact-output 改行を減らしたコンパクトな出力形式
-r --raw-output 文字列の引用符を外す --- ## あとは流れでシェル芸に ``` $ 省略 | jq -r '.Reservations[].Instances[] | select(.State.Name == "stopped")' '| [ .InstanceId, (.Tags[]? | select(.Key == "Name")).Value ] | @sh' \ | awk '{ print "echo Instance Starting... " $1 " " $2 ";' ' aws ec2 start-instances --instance-ids " $1 }' | sh ``` ### AWSのEC2インスタンス一覧から停止状態のものだけ
を抽出し、インスタンスIDとNameタグだけ awkに渡して
個別にエコー表示、インスタンスを起動するコマンドの
文字列を生成して、それをシェルに渡すといったような
事をやってます。 --- ## CSVの読み込み ``` $ cat sample.csv | printf %s "$(cat)" \ | jq -Rs 'split("\n") | map(split(",")) | map({"fld1": .[0], "fld3": .[2]})' ``` #### -R --raw-input 入力全体を単一の長い文字列として読み込み
-s --slurp 入力オブジェクトを単一の配列にまとめる
map(filter) 配列の各要素に指定したフィルタを適用する関数 ## 引数の変数展開 ``` $ jq -n --arg a 1 --arg b 2 --arg c 3 '{ a: $a, b: $b, c: $c }' ``` ## 文字列内の式展開 ``` $ echo '[2,3,5,7,11]' | jq '"first \(.[0])", "second \(.[1])"' ``` --- ### その他、使えそうな組み込み関数 - ### sort, sort_by
入力配列をソートする - ### unique, unique_by
入力配列の重複を削除する - ### group_by
入力配列をグループ化する - ### add
配列の各要素を数値の場合は合算、文字列は結合 - ### range
指定範囲の数値群を生成する ---
[![oreahyouyaku_jq](img/oreahyouyaku_jq.png)](https://stedolan.github.io/jq/manual/)