jq使用

使用json做客制化配置,一开始每份客制化用一份json配置,直接用复制替换的方式切换,虽然不高明但是很实用。后来领导的要求越来越花哨,大致需要先去解析json的内容,然后再去客制化,这里记录过程中用到的jq操作,方便以后有类似需求时直接参考。
官方文档在这里 ,虽然是英文,但是还算方便,虽说不一定看懂。

使用

  • 较简单使用

    1
    2
    3
    4
    5
    6
    $ cat built.json | jq # 不使用过滤器,则原样输出
    $ cat built.json | jq '.' # 使用 . 过滤器获取 key 的值,这里原样输出
    $ jq '.' built.json # 使用 . 过滤器获取 key 的值,这里原厂输出
    $ jq '.config.built' built.json # 使用 . 过滤器获取 key 的值
    $ jq '.config.built.fw_builtdate | tonumber' built.json # 将格式正确的字符串转换成对应的数字
    $ jq -c '.' built.json # 将json在一行输出
  • 简单使用

    • --slurp/-s参数

      Instead of running the filter for each JSON object in the input, read the entire input stream into a large array and run the filter just once.

      1
      $ jq -s '.[0] * .[1]' built.json irmap.json # 将两份json合并
    • --argjson参数

      将一个json对象给变量赋值。

      1
      2
      SMARTTVJSON=smarttv/smarttv.json
      jq -n --argjson order "$(<"${SMARTTVJSON}")" '{"smarttv":null} | .smarttv = $order' > smarttv.json

      将smarttv.json的内容,转换成json对象,然后把这个json对象,赋给变量order;

      过滤器添加一个smarttv的空key,接着把变量order的值给到smarttv这个key;

      最后把处理后的数据重定向到一个json文件。

    • --slurpfile参数

      将一个json文件给变量赋值。

      1
      2
      3
      COMMON_JSON=public/public.json
      ORDER_JSON=order/order.json
      jq --slurpfile public ${COMMON_JSON} 'paths(scalars) as $order | $public[] | getpath($order)' ${ORDER_JSON}

      将public.json文件,赋给变量public;

      过滤器,将order.json文件的非null(这个不太理解,只是刚好功能OK)的key的路径赋给order变量,然后拿到public.json对应的这些路径的key的值(如果是null,说明public.json没有这个key)。

      过滤器这样设计,是要找出order.json里比public.json多的有效值(这个key的值不是null)。

      paths(scalars)builtin.jq里的定义:

      1
      2
      3
      def scalars: select(type|. != "array" and . != "object");
      def paths(node_filter): . as $dot|paths|select(. as $p|$dot|getpath($p)|node_filter);
      def leaf_paths: paths(scalars);
    • -f参数

      从文件中读取过滤器。

      1
      jq -f mergeorder.jq -s public.json order.json > order.json

      过滤器mergeorder.jq内容如下:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      def mergeorder(a;b):
      reduce b[] as $item (a;
      reduce ($item | keys_unsorted[]) as $key (.;
      $item[$key] as $val | ($val | type) as $type | .[$key] = if ($type == "object") then
      mergeorder({}; [if .[$key] == null then {} else .[$key] end, $val])
      elif ($type == "null") then
      .[$key]
      else
      $val
      end)
      );
      mergeorder({}; .)
  • 😂

交叉编译

  1. 准备交叉编译链

    1
    $ tar -xf asdk-6.4.1-a55-EL-4.4-g2.26-a32nut-170810.tar.bz2
  2. 配置环境变量

    1
    $ vim /etc/profile

    添加

    1
    export PATH=$PATH:/home/xtg1800/asdk-6.4.1-a55-EL-4.4-g2.26-a32nut-170810/bin

    使环境变量即时生效

    1
    $ source /etc/profile

    检查交叉编译链是否配置成功

    1
    2
    3
    4
    5
    6
    7
    8
    $ arm-linux-gcc -v
    Using built-in specs.
    COLLECT_GCC=/home/xtg1800/asdk-6.4.1-a55-EL-4.4-g2.26-a32nut-170810/bin/arm-linux-gnueabi-xgcc
    COLLECT_LTO_WRAPPER=/home/xtg1800/asdk-6.4.1-a55-EL-4.4-g2.26-a32nut-170810/bin/../libexec/gcc/arm-linux-gnueabi/6.4.1/lto-wrapper
    Target: arm-linux-gnueabi
    Configured with: Realtek SDK Builder release 5
    Thread model: posix
    gcc version 6.4.1 20170707 (Realtek ASDK-6.4.1 Build 2641)
  3. 准备jq代码

    1
    2
    $ git clone https://github.com/stedolan/jq.git
    $ cd jq
  4. 配置并编译

    1
    2
    3
    4
    $ git submodule update --init
    $ autoreconf -fi
    $ CC=arm-linux-gcc ./configure --host=arm --disable-maintainer-mode --with-oniguruma=builtin
    $ make LDFLAGS=-all-static
  5. 检查

    1
    2
    $ file jq
    jq: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, for GNU/Linux 3.2.0, BuildID[sha1]=84b312b91d525513129861f40ef6359ee0188eb0, not stripped
  6. 最后

    把这个二进制文件预置到开发板就可以使用啦

上述提到的这个例子

1
jq -f mergeorder.jq -s public.json order.json > order.json

发现有问题(用的是1.6版本的jq),还是说其实是过滤器有问题?不确定,留个心眼。

当把一个json文件当做input时,不能同时重定向作为jq处理后的输出,否则结果跟预想的可能不一样。

以下命令,输出总是对的:

1
$ jq -f mergeorder.jq -s public.json order.json

但是重新重定向到order.json后,结果就不一样。

因为这个差异,卡了好久!

最后这样处理,就能按预想的跑了:

1
2
cp order.json order_bak.json
jq -f mergeorder.jq -s public.json order_bak.json > order.json

参考

如何使用JQ合并2个 JSON文件?

How to merge two JSON files using jq or any tool?

How to merge 2 JSON objects from 2 files using jq?

Shell:无比强大的shell之json解析工具jq , Linux命令行解析json, jq解析 json 实例

JSON格式化输出和解析工具 - jq

Merging JSON files recursively in the command-line

Cross-compilation