jq工具-菜刀在手天下我有
jq命令是一款功能强大的命令行json解析工具。支持诸如: 选择,迭代,归约(reduce)等各种操作方式去处理json文档。jq也可以接受文本输入,但默认情况下,jq从标准输入(stdin)读取一系列json实体(包括数字和其他字面量)。可以将一个jq程序看作一个过滤器,处理输入数据,按照规则过滤数据,产生输出数据。jq内置许多标准的过滤器,可以过滤json对象的特定字段,数据类型转换,或其他各种标准任务。各个filter之间支持级联,也支持将多个filter的输出归并至一个数组中。
基本用法
jq命令基本形式: jq + 过滤规则 + json文件或json字符串。
- 文件读取,
jq . test.json或者jq . -f test.json - 标准输入,
echo '{"prices":[1,2]}' | jq .
常用参数
- 参数–slurp|-s: 当输入内容是多个json对象时,将多个json对象视为1个json数组
- 参数-n: 不读取任何内容,使用 jq 构造数据时可以使用
- 参数-c: 表示紧凑的打印输出内容
- 参数–color-output|-C: 强制高亮显示,默认只在终端输出才会高亮显示
- 参数-e|–exit-status: 根据获取到的结果决定退出码是多少
- 参数–tab: 使用tab作为缩进符,而不是使用2个空格符号
- 参数–indent: 使用指定数量的空格符作为缩进符
- 参数–arg: 输入key-value参数,在过滤表达式中引用($key)
- 参数–args: 位置参数,在过滤表达式中引用($ARGS.positional[])
- 参数–argjson: 与arg类似,value接受一个json字符串
- 参数–jsonargs: value接受一个json数组,在过滤表达式中引用($ARGS.positional[])
- 参数–slurpfile: 形式key-file,将指定文件读入保存在指定的变量
特殊符号
句号(.)作为最特殊的过滤器,作用是将输入的json字符串原样输出。逗号(,)的作用是将两个过滤器的结果连接起来。被逗号分隔的两个过滤器会从相同的输入数据中生成各自的输出值流,然后依次将这两个过滤器的输出结果串联起来:先输出左侧表达式的所有结果,然后输出右侧表达式的所有结果。管道(|)的作用与shell中的管道作用一致,连接两个过滤器,将前一个过滤器的结果作为后者的输入。括号(())的作用与大多数编程语言中的括号类似,用作分组操作符。$ENV可以用来在过滤器中引用环境变量
基本运算符
jq支持常见的算数运算符号,+-*/%的同时也支持逻辑运算符号and|or|not
- +,
echo '{"a": 7}' | jq '.a + 1' - -,
echo '["xml", "yaml", "json"]' | jq '. - ["xml", "yaml"]' - */%,
jq -n '3/2*5%2' - and,
jq '(true, true) and (true, false)' - or,
jq -n '(true, false) or false' - not,
jq -n '[true, false | not]' - 切片,
echo '[1,2,3,4,5,6,7,8,9]' | jq '.[1:5]'
类型构造
使用当前的json字符串构造生成新的符合要求的json对象也是常见使用场景
echo '{"user":"stedolan","projects": ["jq", "wikiflow"]}' | jq '[.user, .projects[]]'
echo '{"user":"stedolan","titles":["JQ Primer", "More JQ"]}' | jq '{user, title: .titles[]}'
echo '{"user":"stedolan","titles":["JQ Primer", "More JQ"]}' | jq '{(.user): .titles}'
注意: 上面的例子中的and和or,对数据生成笛卡尔集,然后再评估逻辑结果and例输出,[true, false, true, false], or例输出,[true, false]。(如果这些运算符的某个操作数会生成多个结果,则该运算符本身会针对每个输入生成结果结果。)
内置函数
- map函数,
echo '[1,2]' | jq -c 'map(.+1)',输出:[2,3] - map_values函数,
echo '{"a": 1}' | jq -c 'map_values(.+1)',输出:{“a”:2} - reduce函数,
echo '[1,2]' | jq 'reduce .[] as $i (0; . + $i)',输出:3 - length函数,
echo '[[1], "i", {"a": 2}]' | jq -c 'map(length)',输出:[1,1,1] - keys函数,
echo '{"abc": 1, "Foo": 3}' | jq -c 'keys',输出:[“Foo”,“abc”] - in函数,
echo '["foo", "bar"]' | jq 'map(in({"foo": 42}))',输出:[true,false] - has函数,
echo '[{"a": 0}, {"b": "1"}]' | jq 'map(has("a"))',输出:[true,false] - del函数,
echo '{"a": 0, "b": 1, "c": 2}' | jq -c 'del(.a)',输出:{“b”:1,“c”:2} - setpath函数,
echo '{"a":{"b":0}}' | jq 'setpath(["a","b"]; 1)',输出:{“a”:{“b”:1}} - getpath函数,
echo '{"a":{"b":0}}' | jq -c 'getpath(["a","b"])',输出:0 - explode函数,
echo '"foobar"' | jq -c 'explode',输出:[102,111,111,98,97,114] - implode函数,
echo '[65, 66, 67]' | jq -c 'implode',输出:“ABC” - split函数,
echo '"a, b,c,d, e, "' | jq -c 'split(", ")',输出:[“a”,“b,c,d”,“e”,""] - join函数,
echo '["a","b,c,d","e"]' | jq 'join(", ")',输出:“a, b,c,d, e” - ascii_downcase函数,
echo '"Aa"' | jq -c 'ascii_downcase',输出:“aa” - ascii_upcase函数,
echo '"Aa"' | jq -c 'ascii_upcase',输出:“AA” - ltrimstr函数,
echo '["foob", "afoo"]' | jq -c 'map(ltrimstr("foo"))',输出:[“b”,“afoo”] - rtrimstr函数,
echo '["foob", "afoo"]' | jq -c 'map(rtrimstr("foo"))',输出:[“foob”,“a”] - contains函数,
echo '"foobar"' | jq 'contains("bar")',输出:true - inside函数,
echo '"bar"' | jq 'inside("foobar")',输出:true - startswith函数,
echo '["fo", "foob"]' | jq -c 'map(startswith("foo"))',输出:[false,true] - endswith函数,
echo '"foobar"' | jq -c 'endswith("foo")',输出:false - to_entries函数,
echo '{"a": 1}' | jq -c 'to_entries',输出:[{“key”:“a”,“value”:1}] - from_entries函数,
echo '[{"key":"a", "value":1}]' | jq -c 'from_entries',输出:{“a”:1} - with_entries函数,
echo '{"a": 1}' | jq -c 'with_entries(.key |= "t" + .)',输出:{“ta”:1} - select函数,
echo '[1,5,3,0]' | jq -c 'map(select(. >= 2))',输出:[5,3] - add函数,
echo '["a","b","c"]' | jq 'add',输出:“abc” - any函数,
echo '[true, false]' | jq 'any',输出:true - all函数,
echo '[true, false]' | jq 'all',输出:false - flatten函数,
echo '[1, [2], [[3]]]' | jq 'flatten',输出:[1,2,3] - range函数,
jq -nc '[range(2;4)]',输出:[2,3] - floor函数,
echo '3.14159' | jq 'floor',输出:3 - sqrt函数,
echo '9' | jq 'sqrt',输出:3 - tonumber函数,
echo '[1, "1"]' | jq -c 'map(tonumber)',输出:[1,1] - tostring函数,
echo '[1, "1", [1]]' | jq -c 'map(tostring)',输出:[“1”,“1”,"[1]"] - sort函数,
echo '[8,3,null,6]' | jq -c 'sort',输出:[null,3,6,8] - min函数,
echo '[5,4,2,7]' | jq 'min',输出:2 - unique函数,
echo '[1,2,5,3,5,3,1,3]' | jq -c 'unique',输出:[1,2,3,5] - reverse函数,
echo '[1,2,3,4]' | jq -c 'reverse',输出:[4,3,2,1] - index函数,
echo '"a,b, cd, efg, hijk"' | jq -c 'index(", ")',输出:3 - rindex函数,
echo '"a,b, cd, efg, hijk"' | jq -c 'rindex(", ")',输出:12 - indices函数,
echo '"a,b, cd, efg, hijk"' | jq -c 'indices(", ")',输出:[3,7,12] - sort_by函数,
echo '[{"f":4}, {"f":3}]' | jq -c 'sort_by(.f)',输出:[{“f”:3},{“f”:4}] - unique_by函数,
echo '[{"f": 1}, {"f": 1}]' | jq -c 'unique_by(.f)',输出:[{“f”:1}] - max_by函数,
echo '[{"f":1}, {"f":2, "b":3}]' | jq -c 'max_by(.f)',输出:{“f”:2,“b”:3} - combinations函数,
echo '[[1,2], [3]]' | jq -c '[combinations]',输出:[[1,3],[2,3]] - type函数,
echo '[{}, null]' | jq -c 'map(type)',输出:[“object”,“null”]
高级技巧
变量
通过一些案例来深入学习和强化jq工具的使用。例如,在compile_commands.json数据库中,如何查询特定源文件的编译命令及其编译参数,结合GCC的预处理选项,这种方法能够方便地展开源文件中引用的宏,极大地有助于源码分析和理解。
echo '[{"addr":{"city":"WH", "stress":"1"}},{"addr":{"city":"NY","stress":"2"}}]' | jq -c --arg city "NY" ' .[] | .addr.city = $city '
echo '{"name": "", "age": ""}' | jq --args '.name=$ARGS.positional[0] | .age=$ARGS.positional[1]' "John Doe" 30
cat compile_commands.json
[
{
"command": "gcc -Wp,-MMD,fs/.mpage.o.d -nostdinc -isystem /usr/lib/gcc/x86_64-linux-gnu/9/include -I./arch/x86/include -I./arch/x86/include/generated -I./include -I./arch/x86/include/uapi -I./arch/x86/include/generated/uapi -I./include/uapi -I./include/generated/uapi -include ./include/linux/compiler-version.h -include ./include/linux/kconfig.h -include ./include/linux/compiler_types.h -D__KERNEL__ -fmacro-prefix-map=./= -Wall -Wundef -Werror=strict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -fshort-wchar -fno-PIE -Werror=implicit-function-declaration -Werror=implicit-int -Werror=return-type -Wno-format-security -std=gnu89 -mno-sse -mno-mmx -mno-sse2 -mno-3dnow -mno-avx -fcf-protection=none -m64 -falign-jumps=1 -falign-loops=1 -mno-80387 -mno-fp-ret-in-387 -mpreferred-stack-boundary=3 -mskip-rax-setup -mtune=generic -mno-red-zone -mcmodel=kernel -Wno-sign-compare -fno-asynchronous-unwind-tables -mindirect-branch=thunk-extern -mindirect-branch-register -fno-jump-tables -fno-delete-null-pointer-checks -Wno-frame-address -Wno-format-truncation -Wno-format-overflow -Wno-address-of-packed-member -O2 --param=allow-store-data-races=0 -Wframe-larger-than=2048 -fstack-protector-strong -Wimplicit-fallthrough=5 -Wno-main -Wno-unused-but-set-variable -Wno-unused-const-variable -fomit-frame-pointer -fno-stack-clash-protection -g -Wdeclaration-after-statement -Wvla -Wno-pointer-sign -Wno-stringop-truncation -Wno-array-bounds -Wno-stringop-overflow -Wno-restrict -Wno-maybe-uninitialized -fno-strict-overflow -fno-stack-check -fconserve-stack -Werror=date-time -Werror=incompatible-pointer-types -Werror=designated-init -Wno-packed-not-aligned -DKBUILD_MODFILE='\"fs/mpage\"' -DKBUILD_BASENAME='\"mpage\"' -DKBUILD_MODNAME='\"mpage\"' -D__KBUILD_MODNAME=kmod_mpage -c -o fs/mpage.o fs/mpage.c",
"directory": "/home/peter/Public/qemu/src",
"file": "/home/peter/Public/qemu/src/fs/mpage.c"
},
{
"command": "gcc -Wp,-MMD,fs/.remap_range.o.d -nostdinc -isystem /usr/lib/gcc/x86_64-linux-gnu/9/include -I./arch/x86/include -I./arch/x86/include/generated -I./include -I./arch/x86/include/uapi -I./arch/x86/include/generated/uapi -I./include/uapi -I./include/generated/uapi -include ./include/linux/compiler-version.h -include ./include/linux/kconfig.h -include ./include/linux/compiler_types.h -D__KERNEL__ -fmacro-prefix-map=./= -Wall -Wundef -Werror=strict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -fshort-wchar -fno-PIE -Werror=implicit-function-declaration -Werror=implicit-int -Werror=return-type -Wno-format-security -std=gnu89 -mno-sse -mno-mmx -mno-sse2 -mno-3dnow -mno-avx -fcf-protection=none -m64 -falign-jumps=1 -falign-loops=1 -mno-80387 -mno-fp-ret-in-387 -mpreferred-stack-boundary=3 -mskip-rax-setup -mtune=generic -mno-red-zone -mcmodel=kernel -Wno-sign-compare -fno-asynchronous-unwind-tables -mindirect-branch=thunk-extern -mindirect-branch-register -fno-jump-tables -fno-delete-null-pointer-checks -Wno-frame-address -Wno-format-truncation -Wno-format-overflow -Wno-address-of-packed-member -O2 --param=allow-store-data-races=0 -Wframe-larger-than=2048 -fstack-protector-strong -Wimplicit-fallthrough=5 -Wno-main -Wno-unused-but-set-variable -Wno-unused-const-variable -fomit-frame-pointer -fno-stack-clash-protection -g -Wdeclaration-after-statement -Wvla -Wno-pointer-sign -Wno-stringop-truncation -Wno-array-bounds -Wno-stringop-overflow -Wno-restrict -Wno-maybe-uninitialized -fno-strict-overflow -fno-stack-check -fconserve-stack -Werror=date-time -Werror=incompatible-pointer-types -Werror=designated-init -Wno-packed-not-aligned -DKBUILD_MODFILE='\"fs/remap_range\"' -DKBUILD_BASENAME='\"remap_range\"' -DKBUILD_MODNAME='\"remap_range\"' -D__KBUILD_MODNAME=kmod_remap_range -c -o fs/remap_range.o fs/remap_range.c",
"directory": "/home/peter/Public/qemu/src",
"file": "/home/peter/Public/qemu/src/fs/remap_range.c"
},
.....
]
jq '.[]| select(.file|contains("cgroup/cgroup.c"))' compile_commands.json
{
"command": "gcc -Wp,-MMD,kernel/cgroup/.cgroup.o.d -nostdinc -isystem /usr/lib/gcc/x86_64-linux-gnu/9/include -I./arch/x86/include -I./arch/x86/include/generated -I./include -I./arch/x86/include/uapi -I./arch/x86/include/generated/uapi -I./include/uapi -I./include/generated/uapi -include ./include/linux/compiler-version.h -include ./include/linux/kconfig.h -include ./include/linux/compiler_types.h -D__KERNEL__ -fmacro-prefix-map=./= -Wall -Wundef -Werror=strict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -fshort-wchar -fno-PIE -Werror=implicit-function-declaration -Werror=implicit-int -Werror=return-type -Wno-format-security -std=gnu89 -mno-sse -mno-mmx -mno-sse2 -mno-3dnow -mno-avx -fcf-protection=none -m64 -falign-jumps=1 -falign-loops=1 -mno-80387 -mno-fp-ret-in-387 -mpreferred-stack-boundary=3 -mskip-rax-setup -mtune=generic -mno-red-zone -mcmodel=kernel -Wno-sign-compare -fno-asynchronous-unwind-tables -mindirect-branch=thunk-extern -mindirect-branch-register -fno-jump-tables -fno-delete-null-pointer-checks -Wno-frame-address -Wno-format-truncation -Wno-format-overflow -Wno-address-of-packed-member -O2 --param=allow-store-data-races=0 -Wframe-larger-than=2048 -fstack-protector-strong -Wimplicit-fallthrough=5 -Wno-main -Wno-unused-but-set-variable -Wno-unused-const-variable -fomit-frame-pointer -fno-stack-clash-protection -g -Wdeclaration-after-statement -Wvla -Wno-pointer-sign -Wno-stringop-truncation -Wno-array-bounds -Wno-stringop-overflow -Wno-restrict -Wno-maybe-uninitialized -fno-strict-overflow -fno-stack-check -fconserve-stack -Werror=date-time -Werror=incompatible-pointer-types -Werror=designated-init -Wno-packed-not-aligned -DKBUILD_MODFILE='\"kernel/cgroup/cgroup\"' -DKBUILD_BASENAME='\"cgroup\"' -DKBUILD_MODNAME='\"cgroup\"' -D__KBUILD_MODNAME=kmod_cgroup -c -o kernel/cgroup/cgroup.o kernel/cgroup/cgroup.c",
"directory": "/home/peter/Public/qemu/src",
"file": "/home/peter/Public/qemu/src/kernel/cgroup/cgroup.c"
}
条件表达式
使用条件表达式可以帮助用户在大量数据中,过滤并生成有用数据
echo '{"users":[{"name":"a","age":26},{"name":"b","age":25}]}' | jq '.users[] | if .age > 25 then .adult = true else .adult = false end'
{
"name": "a",
"age": 26,
"adult": true
}
{
"name": "b",
"age": 25,
"adult": false
}
调试
debug函数可以帮助使用者在多个过滤器中打印中间数据供观察调试
echo '{"users":[{"name":"a","age":26},{"name":"b","age":25}]}' | jq '.users[]| debug | if .age > 25 then .adult = true else .adult = false end'
["DEBUG:",{"name":"a","age":26}]
{
"name": "a",
"age": 26,
"adult": true
}
["DEBUG:",{"name":"b","age":25}]
{
"name": "b",
"age": 25,
"adult": false
}
导入模块
jq命令允许用户将常见的过滤条件或规则写入独立的模块文件(后缀为 .jq),方便重复调用和使用。
echo '[1,2]' | jq 'def addvalue(f): f + 2; map(addvalue(.))'
[
3,
4
]
错误处理
使用try-catch使用语句jq更为灵活, 比如:jq过滤器在访问无效索引时,通常会抛出错误。下面例子中,希望获取对象中的.name的相关元素,实际执行过程中jq抛出异常: cannot index string with string name。
echo '"test"' | jq '.name'
jq: error (at <stdin>:1): Cannot index string with string "name"
echo '"test"' | jq 'try .name catch "No name found"'
"No name found"
源码赏析
唉,明知山有虎,偏向虎山行
望闻问切,来源于中医诊断,一般用于强调问题诊断和处理的过程,对应发现、分析和解决问题的流程。事实上,将其应用于程序故障处理更为贴切。不过,在这里我们将“问题”的概念泛化,扩展到源码解析与理解的场景中。
望,观察源码的外在表现
目录结构:
- .pc,使用quilt管理补丁(quilt维护的内部文件置于.pc目录)
- src,jq的源码目录,ChangeLog(工具提取git-log),configure.ac,config/m4等常见文件
- docs/Gemfile,ruby中用于列出和管理项目所需包的文件,具体使用未知
- debian,debian打包源码特有,描述debian包的安装,说明等信息
- .travis.yml,使用travis的CICD工具(其他文章已介绍)
- 其他文件含义用途未知,但相对于本篇文章不重要
重点关注src目录中的相关文件:
- src/main.c,处理命令行参数,输入输出,程序入口。
- parser.y, lexer.l,The parser for jq programs. Uses Flex and Bison.
- src/jv*.h, src/jv*.c,内部的json库。src/jv.c包含一些通用的基础api,src/jv_aux.c是对其的一些封装。
- src/jv_parse.c,src/jv_print.c分别包含json的解析和打印函数。
- src/builtin.jq
This contains the jq-coded builtins.
src/jv_parse.c and src/jv_print.c contain the JSON parser and printer, respectively, which jq uses to parse input and render output (these are different from the parser in src/parser.y, which is used to parse jq programs).
src/compile.[ch], src/linker.c, src/bytecode.[ch], src/execute.c, and others The compiler lives in compile.[ch]. These functions are called by the parser to build an internal representation (block form), which gets linked by the linker, and finally gets compiled into bytecode. The bytecode then interpreted by the interpreter, which lives in execute.c.
The interpreter has a supporting cast that handle various runtime aspects of jq, including forkable_stack.h (the guts of jq’s stack, used to implement backtracking) and builtin.h (which defines built-in functions).
tree -a
.
├── appveyor.yml
├── AUTHORS
├── build
├── ChangeLog
├── compile-ios.sh
├── config
│ └── m4
│ ├── check-math-func.m4
│ ├── find-func.m4
│ ├── find-func-no-libs2.m4
│ ├── find-func-no-libs.m4
│ └── misc.m4
├── configure.ac
├── COPYING
├── debian
│ ├── changelog
│ ├── control
│ ├── copyright
│ ├── gbp.conf
│ ├── jq.docs
│ ├── jq.install
│ ├── libjq1.install
│ ├── libjq1.symbols
│ ├── libjq-dev.install
│ ├── patches // 已应用的patches
│ │ ├── 0007-stop-using-libtool-bin.patch
│ │ ├── 0008-Do-not-use-venderized-oniguruma.patch
│ │ ├── 0009-Hardcode-version-to-1.6.patch
│ │ ├── 0010-initialized-variables.patch
│ │ ├── disable-static-libtool.patch
│ │ ├── dont-distribute-duplicate-docs.patch
│ │ ├── enable-manpages.patch
│ │ ├── fix-ftbfs-when-localtime-is-dst.patch
│ │ ├── patch-version-into-build.patch
│ │ ├── remove-unecessary-rakefile-deps.patch
│ │ ├── series
│ │ └── stack-exhaustion.patch
│ ├── rules
│ ├── source
│ │ └── format
│ └── watch
├── Dockerfile
├── docs
│ ├── content
│ │ ├── 1.tutorial
│ │ │ └── default.yml
│ │ ├── 2.download
│ │ │ └── default.yml
│ │ ├── 3.manual
│ │ │ ├── manual.yml
│ │ │ ├── v1.3
│ │ │ │ └── manual.yml
│ │ │ ├── v1.4
│ │ │ │ └── manual.yml
│ │ │ ├── v1.5
│ │ │ │ └── manual.yml
│ │ │ └── v1.6
│ │ │ └── manual.yml
│ │ └── index
│ │ └── index.yml
│ ├── Gemfile
│ ├── Gemfile.lock
│ ├── public
│ │ ├── css
│ │ │ └── base.scss
│ │ ├── .htaccess
│ │ ├── jq.png
│ │ ├── js
│ │ │ └── manual-search.js
│ │ └── robots.txt
│ ├── Rakefile
│ ├── Rakefile.manual
│ ├── Rakefile.website
│ ├── README.md
│ ├── site.yml
│ └── templates
│ ├── default.liquid
│ ├── index.liquid
│ ├── manual.liquid
│ └── shared
│ ├── _footer.liquid
│ ├── _head.liquid
│ └── _navbar.liquid
├── .github
│ └── ISSUE_TEMPLATE
│ └── bug_report.md
├── .gitmodules
├── jq.1.prebuilt
├── jq.spec
├── KEYS
├── m4
│ ├── ax_compare_version.m4
│ └── ax_prog_bison_version.m4
├── Makefile.am
├── modules
│ └── oniguruma
├── NEWS
├── .pc // quilt内部维护的文件,包含相关patch的源文件
│ ├── 0007-stop-using-libtool-bin.patch
│ │ ├── Makefile.am
│ │ └── tests
│ │ └── setup
│ ├── 0008-Do-not-use-venderized-oniguruma.patch
│ │ └── Makefile.am
│ ├── 0009-Hardcode-version-to-1.6.patch
│ │ └── scripts
│ │ └── version
│ ├── 0010-initialized-variables.patch
│ │ └── src
│ │ └── jq_test.c
│ ├── applied-patches
│ ├── disable-static-libtool.patch
│ │ ├── Makefile.am
│ │ └── tests
│ │ └── setup
│ ├── dont-distribute-duplicate-docs.patch
│ │ └── Makefile.am
│ ├── enable-manpages.patch
│ │ └── Makefile.am
│ ├── fix-ftbfs-when-localtime-is-dst.patch
│ │ └── src
│ │ └── builtin.c
│ ├── patch-version-into-build.patch
│ │ └── configure.ac
│ ├── .quilt_patches
│ ├── .quilt_series
│ ├── remove-unecessary-rakefile-deps.patch
│ │ └── docs
│ │ └── Rakefile
│ ├── stack-exhaustion.patch
│ │ └── src
│ │ └── jv_print.c
│ └── .version
├── README -> README.md
├── README.md
├── scripts
│ ├── crosscompile
│ ├── gen_utf8_tables.py
│ ├── update-website
│ └── version
├── sig
│ ├── jq-release.key
│ ├── v1.3
│ │ ├── jq-linux-x86_64.asc
│ │ ├── jq-linux-x86.asc
│ │ ├── jq-osx-x86_64.asc
│ │ ├── jq-osx-x86.asc
│ │ ├── jq-win32.exe.asc
│ │ ├── jq-win64.exe.asc
│ │ └── sha256sum.txt
│ ├── v1.4
│ │ ├── jq-linux-x86_64.asc
│ │ ├── jq-linux-x86.asc
│ │ ├── jq-osx-x86_64.asc
│ │ ├── jq-osx-x86.asc
│ │ ├── jq-solaris11-32.asc
│ │ ├── jq-solaris11-64.asc
│ │ ├── jq-win32.exe.asc
│ │ ├── jq-win64.exe.asc
│ │ └── sha256sum.txt
│ ├── v1.5
│ │ ├── jq-linux32.asc
│ │ ├── jq-linux32-no-oniguruma.asc
│ │ ├── jq-linux64.asc
│ │ ├── jq-osx-amd64.asc
│ │ ├── jq-win32.exe.asc
│ │ ├── jq-win64.exe.asc
│ │ └── sha256sum.txt
│ ├── v1.5rc1
│ │ ├── jq-linux-x86_64-static.asc
│ │ ├── jq-win32.exe.asc
│ │ ├── jq-win64.exe.asc
│ │ └── sha256sum.txt
│ ├── v1.5rc2
│ │ ├── jq-linux-x86_64.asc
│ │ ├── jq-linux-x86.asc
│ │ ├── jq-osx-x86_64.asc
│ │ ├── jq-win32.exe.asc
│ │ ├── jq-win64.exe.asc
│ │ └── sha256sum.txt
│ └── v1.6
│ ├── jq-linux32.asc
│ ├── jq-linux64.asc
│ ├── jq-osx-amd64.asc
│ ├── jq-win32.exe.asc
│ ├── jq-win64.exe.asc
│ └── sha256sum.txt
├── src
│ ├── builtin.c
│ ├── builtin.h
│ ├── builtin.jq
│ ├── bytecode.c
│ ├── bytecode.h
│ ├── compile.c
│ ├── compile.h
│ ├── exec_stack.h
│ ├── execute.c
│ ├── inject_errors.c
│ ├── jq.h
│ ├── jq_parser.h
│ ├── jq_test.c
│ ├── jv_alloc.c
│ ├── jv_alloc.h
│ ├── jv_aux.c
│ ├── jv.c
│ ├── jv_dtomain.c
│ ├── jv_dtoa.h
│ ├── jv_file.c
│ ├── jv.h
│ ├── jv_parse.c
│ ├── jv_print.c
│ ├── jv_unicode.c
│ ├── jv_unicode.h
│ ├── jv_utf8_tables.h
│ ├── lexer.c
│ ├── lexer.h
│ ├── lexer.l
│ ├── libm.h
│ ├── linker.c
│ ├── linker.h
│ ├── locfile.c
│ ├── locfile.h
│ ├── main.c
│ ├── opcode_list.h
│ ├── parser.c
│ ├── parser.h
│ ├── parser.y
│ ├── util.c
│ └── util.h
├── tests
│ ├── base64.test
│ ├── base64test
│ ├── jq-f-test.sh
│ ├── jq.test
│ ├── jqtest
│ ├── mantest
│ ├── modules
│ │ ├── a.jq
│ │ ├── b
│ │ │ └── b.jq
│ │ ├── c
│ │ │ ├── c.jq
│ │ │ └── d.jq
│ │ ├── data.json
│ │ ├── .jq
│ │ ├── lib
│ │ │ └── jq
│ │ │ ├── e
│ │ │ │ └── e.jq
│ │ │ └── f.jq
│ │ ├── syntaxerror
│ │ │ └── syntaxerror.jq
│ │ ├── test_bind_order0.jq
│ │ ├── test_bind_order1.jq
│ │ ├── test_bind_order2.jq
│ │ └── test_bind_order.jq
│ ├── onig.supp
│ ├── onig.test
│ ├── onigtest
│ ├── optional.test
│ ├── optionaltest
│ ├── setup
│ ├── shtest
│ ├── torture
│ │ └── input0.json
│ ├── utf8test
│ └── utf8-truncate.jq
└── .travis.yml
63 directories, 205 files
ldd发现jq工具依赖非常少,只依赖libonig.so.5这个正则库,和自身生成的库libjq.so(debian/control文件已说明),依赖jq的工具或者库也很少,目前只有sysdig在使用,社会关系简单。(快点搞正事!你是医生👨⚕️,不是警察👮♂️,中医是按诊疗时长收费的!)
sudo apt-cache depends libjq1
libjq1
依赖: libc6
依赖: libonig5
sudo apt-cache rdepends libjq1
libjq1
Reverse Depends:
jq
libjq1-dbgsym
sysdig
libjq-dev
jq
sysdig
libjq-dev
不到1.5万行代码,兼容linux,windows,mac的同时,实现过滤器的语法解析,规则执行等复杂的操作
cloc .
204 text files.
198 unique files.
101 files ignored.
github.com/AlDanial/cloc v 1.82 T=0.05 s (1935.8 files/s, 815833.7 lines/s)
-------------------------------------------------------------------------------
Language files blank comment code
-------------------------------------------------------------------------------
C 23 2231 1802 19546
YAML 11 3142 97 10013
C/C++ Header 18 263 165 1347
yacc 1 97 10 872
make 7 297 138 867
m4 9 90 53 756
Bourne Shell 16 105 64 495
liquid 6 19 4 237
Sass 1 22 0 159
lex 1 25 7 153
Markdown 3 37 0 90
JavaScript 1 0 2 50
Dockerfile 1 4 2 47
Ruby 2 12 0 46
Python 1 9 1 21
JSON 2 0 0 11
-------------------------------------------------------------------------------
SUM: 103 6353 2345 34710
-------------------------------------------------------------------------------
闻,感知程序运行时的状态与反馈
通过前面章节的Jq工具的基本使用样例, cflow的1.7版本,支持直接导出Dot(图片描述语言)格式的文件,利用Graphviz工具可以将该文件转成图片。
+-main() <int main (int argc, char *argv[]) at main.c:239>
+-jv_array()
+-jv_object()
+-fflush()
+-fileno()
+-CommandLineToArgvW()
+-GetCommandLineW()
+-assert()
+-alloca()
+-WideCharToMultiByte()
+-jq_init()
+-perror()
+-JV_PRINT_INDENT_FLAGS()
+-jq_util_input_init()
+-jv_null()
+-jv_array_append()
+-jv_string()
+-jv_parse()
+-jq_util_input_add_input()
+-strcmp()
+-usage() <void usage (int code, int keep_it_short) at main.c:44>
+-fprintf()
\-exit()
+-isoptish() <int isoptish (const char *text) at main.c:106>
\-isalpha()
+-jv_get_kind()
+-jq_realpath()
+-fprintf()
+-die() <void die () at main.c:97>
+-fprintf()
\-exit()
+-isoption() <int isoption (const char *text, char shortopt, const char *longopt, size_t *short_opts) at main.c:110>
+-strcmp()
\-strchr()
+-atoi()
+-jv_object_has()
+-jv_copy()
+-jv_object_set()
+-jv_is_valid()
+-jv_load_file()
+-jv_invalid_get_msg()
+-jv_string_value()
+-jv_free()
+-jv_array_length()
+-jv_array_get()
+-printf()
+-jq_testsuite()
+-strlen()
+-isatty()
+-getenv()
+-jq_set_colors()
+-JV_ARRAY()
+-jq_set_attr()
+-strdup()
+-exit()
+-dirname()
+-free()
+-strchr()
+-jv_string_fmt()
+-JV_OBJECT()
+-jq_compile_args()
+-skip_shebang() <const char *skip_shebang (const char *p) at main.c:149>
+-strncmp()
\-strchr()
+-jq_dump_disassembly()
+-jq_util_input_set_parser()
+-jv_parser_new()
+-jq_set_input_cb()
+-jq_set_debug_cb()
+-debug_cb() <void debug_cb (void *data, jv input) at main.c:233>
+-jv_dumpf()
+-JV_ARRAY()
+-jv_string()
\-fprintf()
+-process() <int process (jq_state *jq, jv value, int flags, int dumpopts) at main.c:164>
+-jq_start()
+-jv_is_valid()
+-jq_next()
+-jv_get_kind()
+-jv_dumpf()
+-fwrite()
+-jv_string_value()
+-jv_string_length_bytes()
+-jv_copy()
+-jv_free()
+-priv_fwrite()
+-jv_dump()
+-fflush()
+-jq_halted()
+-jq_get_exit_code()
+-jv_number_value()
+-jq_get_error_message()
+-fprintf()
+-jv_dump_string()
+-jv_invalid_has_msg()
+-jv_invalid_get_msg()
\-jq_util_input_get_position()
+-jq_util_input_errors()
+-jq_util_input_next_input()
+-jv_invalid_has_msg()
+-ferror()
+-fclose()
+-strerror()
+-jq_util_input_free()
\-jq_teardown()