jq - 用 startswith & endswith 過濾 JSON 資料
Posted on Sep 12, 2022 in Unix-like 命令列教學 by Amo Chen ‐ 2 min read
jq 是方便且成熟的 JSON 資料操作工具,可以幫助我們快速對 JSON 型態的資料進行擷取(extract)、過濾(filter)、運算(computing)甚至是重組(transform)等操作。
如果是常常需要與 JSON 格式資料打交道的開發者,可以投資一些時間好好熟悉 jq, 不過由於該工具提供各式各樣的功能,所以不免使用前要稍微查閱文件一番。
本文透過實際範例學習如何操作 jq 提供的 startswith
與 endswith
函式進行資料篩選與過濾。
本文環境
- jq 1.6
本文 JSON 範例資料
本文提供 2 種常用的 JSON 格式:
- JSON Lines 檔案中的每 1 行都是 1 組 JSON 格式的資料
- JSON array, 檔案中資料以 JSON 陣列的形式儲存,可以視為 1 個檔案就是 1 組 JSON 格式的資料。
JSON Lines 範例(本文將此範例檔命名為 example.jsonl
):
{"domain": "example.com", "hostname": "abc"}
{"domain": "example.com", "hostname": "def"}
{"domain": "example.com", "hostname": "abcdef"}
JSON array 範例(本文將此範例檔命名為 example
)
[
{"domain": "example.com", "hostname": "abc"},
{"domain": "example.com", "hostname": "def"},
{"domain": "example.com", "hostname": "abcdef"}
]
startswith(str) + JSON Lines
如果想只過濾出 JSON lines 格式的資料,某個特定欄位是特定字串開頭的可使用以下指令:
$ jq -r '. | select(.<the field> | startswith("<the prefix>"))' example.jsonl
p.s. 請將 <the field>
與 <the prefix>
替換成所需要的值
例如下列指令過濾出 JSON Lines 資料中, hostname
是 abc
開頭的資料:
$ jq -r '. | select(.hostname | startswith("abc"))' example.jsonl
執行結果如下,可以看到 def
被排除:
{
"domain": "example.com",
"hostname": "abc"
}
{
"domain": "example.com",
"hostname": "abcdef"
}
如果只保持原本的 JSON Lines 格式,可以加上 -c
/ --compact-output
:
$ jq -rc '. | select(.hostname | startswith("abc"))' example.jsonl
加上 -c
執行結果如下:
{"domain":"example.com","hostname":"abc"}
{"domain":"example.com","hostname":"abcdef"}
startswith(str) + JSON array
如果想只過濾出 JSON array 格式的資料,某個特定欄位是特定字串開頭的則可使用以下指令(可以看到指令與 JSON Lines 的過濾指令差了 .[]
的部分):
$ jq -r '.[] | select(.<the field> | startswith("<the prefix>"))' example
p.s. 請將 <the field>
與 <the prefix>
替換成所需要的值
例如下列指令過濾出 JSON array 資料中, hostname
是 abc
開頭的資料:
$ jq -r '.[] | select(.hostname | startswith("abc"))' example
執行結果如下,可以看到 def
被排除:
{
"domain": "example.com",
"hostname": "abc"
}
{
"domain": "example.com",
"hostname": "abcdef"
}
如果要維持 JSON array 的格式可以改為用 map(x)
函式進行過濾:
$ jq -r 'map(select(.hostname | startswith("abc")))' example
map(x)
is equivalent to[.[] | x]
運用 map(x)
其實等同於 [.[] | x]
的寫法,以 'map(select(.hostname | startswith("abc")))'
為例的話,等同於:
[.[] | select(.hostname | startswith("abc"))]
endswith(str)
學會使用 startswith(str)
之後,想要過濾某個特定欄位是特定字串結尾的話,只要將前述指令中的 startswith
改為 endswith
即可,例如以下指令只過濾出 hostname
欄位是 def
結尾的資料:
$ jq -r 'map(select(.hostname | endswith("def")))' example
$ jq -rc '. | select(.hostname | endswith("def"))' example.jsonl
References
https://stedolan.github.io/jq/manual/