顯示具有 comm 標籤的文章。 顯示所有文章
顯示具有 comm 標籤的文章。 顯示所有文章

2019年9月20日 星期五

jq 指令筆記 - 整理 JSON 資料,使用 select / index 過濾關鍵字

用 jq 去整理 api/json 的資料的。整個需求是:

  • API 回傳的 JSON 資料中,是一個 array 形式,裡頭的元素是 key-value pair
  • 透過 jq 把符合我需要的 資料列出
  • 檢查在某些條件上,有哪些東西,最後回歸到 comm 的工具幫忙導出結果進行比較

筆記一下 jq 項目:

$ cat /tmp/api.json | jq '.["data"]'
[
  {
    "field": "hello"
  },
  {
    "field": "world"
  }
]
$ cat /tmp/api.json | jq '.["data"] | .[] '
{
  "field": "hello"
}
{
  "field": "world"
}
$ cat /tmp/api.json | jq '.["data"] | .[] | select (.field | index("e") > 0) '
{
  "field": "hello"
}
$ cat /tmp/api.json | jq '.["data"] | .[] | select (.field | index("e") > 0) | .field '
"hello"


如此,可以結果導入檔案,如果需要比較檔案內的差異,就可以用 comm 指令來做事

使用 comm 指令,找尋存在 A 檔案卻不在 B 檔案內的關鍵字

這個需求是為了過濾一些條件,找出某筆資料存在 A 檔案,卻不在 B 檔案的用法。這時用 comm 這個指令就能達成功效(通常都還會用 sort/uniq 指令搭配):

$ cat /tmp/a.log
1
2
3
4
5


$ cat /tmp/b.log
3
5
8
9


$ comm -23 /tmp/a.log /tmp/b.log
1
2
4

2015年8月1日 星期六

使用 jq、awk、sort、uniq、tail、diff、comm 處理 JSON 大檔

跟朋友相約參加了黑客松,主要是分析 SPAM 資訊,由於官方提供的是一個很大檔案的 json format,大多操作都適用 jq 指令處理,盡量不寫 code 來分析 XD

首先,只對指定欄位取出資料:

$ cat data_set.input
[
   { "field1":"1" , "field2": "2", "field3": 3, "field4" : [1, 2, 3] } ,
   { "field1":"a" , "field2": "b", "field3": 4, "field4" : [1, 2] } ,
   ...
}


$ < data_set.file jq '.[] | .field1 +"-" + .field2 '
"1-2"
"a-b"
...


有時會碰到資料欄位是 number ,這時會出現 string and number cannot be added 的部分,可以這樣做:

$ < data_set.input jq '.[] | .field1 +"-" + (.field3 | tostring) '
"1-3"
"a-4"
...


有時想看某個欄位個數:

$ < data_set.input jq '.[] | .field1 +"-" + (.field4 | length | tostring) '
"1-3"
"a-2"
...


接著偷懶用 awk 整理資料:

$ < data_set.file jq '.[] | .field1 +"-" + .field2 ' | awk -F'"' '{print $2}'
1-2
a-b
...


有時需要判斷數值大小後,來決定是否輸出:

$ < data_set.file awk -F'-' '{ if($2 > 10) { print $1 }}'

輸出後,可以透過 sort 跟 uniq 整理一下:

$ < data_set.file awk -F'-' '{ if($2 > 10) { print $1 }}' | sort | uniq

有時搭配 uniq -c 計算屬性後,再用 sort -n 來排序:

$ < data_set.file awk -F'-' '{ if($2 > 10) { print $1 }}' | sort | uniq -c | sort -n

這時,輸出的結果就有指定屬性從小排到大的特性,如果第 1234 個 line 開始是你要的資料,可以搭配 tail 指令取出:

$ < data_set.file awk -F'-' '{ if($2 > 10) { print $1 }}' | sort | uniq -c | sort -n | tail -n +1234

甚至,取出後再搭配 awk 把前置數字去除,只要重要結果即可:

$ < data_set.file awk -F'-' '{ if($2 > 10) { print $1 }}' | sort | uniq -c | sort -n | tail -n +1234 | awk -F ' ' '{print $2}'

最後,如果有 lookup_pattern 跟 check_data 想要比對,記得都要把兩者做 sort,就可以用 diff 跟 comm 兩個指令:

$ sort lookup_pattern > lookup_pattern.sorted
$ sort check_data > check_data.sorted


這時想要檢查沒有落在 lookup_pattern.sorted 的清單或個數:

$ diff lookup_pattern.sorted check_data.sorted | grep "<"
$ diff lookup_pattern.sorted check_data.sorted | grep -c "<"


那如果想看有 match 到的清單:

$ comm -1 -2 lookup_pattern.sorted check_data.sorted

如此一來就類似作為清單比對的動作。若比較的條件太多時,只好寫寫 python 啦:

#!/usr/bin/python
#
# input.log、p1.log、p2.log 都是以 line 為單位的資料
#

in_data = open('input.log').read().split("\n")

pattern_data1 = open('p1.log').read().split("\n")
pattern_data2 = open('p2.log').read().split("\n")

lookup1 = {}
for i in pattern_data1:
        lookup1[i] = ''

lookup2 = {}
for i in pattern_data2:
        lookup2[i] = ''

for i in in_data:
    if i in lookup1:
         print " data in lookup1"
    elif i in lookup2:
         print " data in lookup2 && not in lookup1"