JSON神器之jq使用指南指北

jq 就像sedJSON 數據一樣 - 您可以使用它來切片、過濾、映射和轉換結構化數據,就像 ,sed和 朋友讓您玩文本一樣容易。awkgrep

jq 是用可移植的 C 語言編寫的,它具有零運行時依賴性。您可以下載單個二進制文件,scp將其下載到同一類型的遙遠機器上,並期望它能夠正常工作。

jq 可以毫不費力地將您擁有的數據格式轉換爲您想要的格式,並且執行此操作的程序通常比您預期的更短更簡單。


快速開始之helloworld

1. 美化輸出Json:

echo '{ "foo": { "bar": { "baz": 123 } } }' | jq '.'

{
  "foo": {
    "bar": {
      "baz": 123
    }
  }
}

 2. 只輸入部分字段

echo '{"foo": 42, "bar": "less interesting data"}' | jq '.foo' 

42

cli 參數

jq 過濾器在 JSON 數據流上運行。jq 的輸入被解析爲一系列以空格分隔的 JSON 值,一次一個地通過提供的過濾器。過濾器的輸出被寫入標準輸出,同樣是一系列以空格分隔的 JSON 數據。

注意:注意 shell 的引用規則很重要。作爲一般規則,最好總是引用(使用單引號字符) jq 程序,因爲太多對 jq 具有特殊含義的字符也是 shell 元字符。例如,jq "foo"在大多數 Unix shell 上會失敗,因爲這與 相同jq foo,通常會失敗,因爲foo is not defined. 使用 Windows 命令 shell (cmd.exe) 時,最好在命令行中給出 jq 程序時使用雙引號(而不是-f program-file選項),但是 jq 程序中的雙引號需要反斜槓轉義。

您可以使用一些命令行選項影響 jq 如何讀取和寫入其輸入和輸出:

  • --version

輸出 jq 版本並以零退出。

  • --seq

使用application/json-seqMIME 類型方案在 jq 的輸入和輸出中分隔 JSON 文本。這意味着在輸出的每個值之前打印一個 ASCII RS(記錄分隔符)字符,並且在每個輸出之後打印一個 ASCII LF(換行符)。無法解析的輸入 JSON 文本將被忽略(但警告),丟棄所有後續輸入,直到下一個 RS。此模式還解析 jq 的輸出而不使用該--seq 選項。

  • --stream

以流方式解析輸入,輸出路徑和葉值數組(標量和空數組或空對象)。例如,"a"變成[[],"a"][[],"a",["b"]] 變成[[0],[]][[1],"a"],和[[1,0],"b"]

這對於處理非常大的輸入很有用。將此與過濾和reduceandforeach語法結合使用,以逐步減少大輸入。

  • --slurp-s:

不要爲輸入中的每個 JSON 對象運行過濾器,而是將整個輸入流讀入一個大數組並只運行一次過濾器。

  • --raw-input-R:

不要將輸入解析爲 JSON。相反,每一行文本都作爲字符串傳遞給過濾器。如果與 結合使用--slurp,則整個輸入將作爲單個長字符串傳遞給過濾器。

  • --null-input-n:

根本不讀取任何輸入!相反,過濾器null作爲輸入運行一次。這在將 jq 用作簡單的計算器或從頭構建 JSON 數據時很有用。

  • --compact-output-c:

默認情況下,jq 漂亮地打印 JSON 輸出。使用此選項將通過將每個 JSON 對象放在一行中來生成更緊湊的輸出。

  • --tab

每個縮進級別使用一個製表符,而不是兩個空格。

  • --indent n

使用給定數量的空格(不超過 7 個)進行縮進。

  • --color-output/-C--monochrome-output-M

默認情況下,如果寫入終端,jq 會輸出彩色 JSON。即使使用 寫入管道或文件,您也可以強制它產生顏色-C,並使用 禁用顏色-M

可以使用JQ_COLORS環境變量配置顏色(見下文)。

  • --binary-b:

使用 WSL、MSYS2 或 Cygwin 的 Windows 用戶在使用本機 jq.exe 時應使用此選項,否則 jq 會將換行符 (LF) 轉換爲回車換行符 (CRLF)。

  • --ascii-output-a:

jq 通常將非 ASCII Unicode 代碼點輸出爲 UTF-8,即使輸入將它們指定爲轉義序列(如“\u03bc”)。使用此選項,您可以強制 jq 生成純 ASCII 輸出,並將每個非 ASCII 字符替換爲等效的轉義序列。

  • --unbuffered

在打印每個 JSON 對象後刷新輸出(如果您將慢速數據源傳送到 jq 並將 jq 的輸出傳送到其他地方,這很有用)。

  • --sort-keys-S:

按排序順序輸出每個對象的字段和鍵。

  • --raw-output-r:

使用此選項,如果過濾器的結果是字符串,那麼它將直接寫入標準輸出,而不是格式化爲帶引號的 JSON 字符串。這對於使 jq 過濾器與非基於 JSON 的系統對話很有用。

  • --join-output-j:

Like-r但 jq 不會在每次輸出後打印換行符。

  • --nul-output-0:

-r,但 jq 將在每次輸出後打印 NUL 而不是換行符。當輸出的值可以包含換行符時,這可能很有用。

  • -f filename--from-file filename:

從文件而不是從命令行讀取過濾器,如 awk 的 -f 選項。您也可以使用“#”來發表評論。

  • -Ldirectory-L directory:

預先directory添加到模塊的搜索列表中。如果使用此選項,則不使用內置搜索列表。請參閱下面的模塊部分。

  • -e--exit-status:

false如果最後一個輸出值不是nor null,則將jq 的退出狀態設置爲 0,如果最後一個輸出值是falseor null,則設置爲 1,如果沒有產生有效結果,則設置爲 4。如果有任何使用問題或系統錯誤,jq 通常退出 2,如果有 jq 程序編譯錯誤,則退出 3,或者如果 jq 程序運行,則退出 0。

另一種設置退出狀態的方法是使用halt_error 內置函數。

  • --arg name value

此選項將值作爲預定義變量傳遞給 jq 程序。如果您使用 運行 jq --arg foo bar,則$foo在程序中可用並具有值"bar"。請注意, value將被視爲字符串,因此--arg foo 123將綁定$foo"123".

jq 程序也可以使用命名參數作爲 $ARGS.named.

  • --argjson name JSON-text

此選項將 JSON 編碼的值作爲預定義變量傳遞給 jq 程序。如果您使用 運行 jq --argjson foo 123,則 $foo在程序中可用並具有值123

  • --slurpfile variable-name filename

此選項讀取命名文件中的所有 JSON 文本,並將解析的 JSON 值的數組綁定到給定的全局變量。如果您使用 運行 jq --slurpfile foo bar,則$foo在程序中可用,並且有一個數組,其元素對應於名爲 的文件中的文本bar

  • --rawfile variable-name filename

此選項讀入命名文件並將其內容綁定到給定的全局變量。如果你運行 jq with --rawfile foo bar, then$foo在程序中是可用的,並且有一個字符串,其內容是文件中的 texs 名爲bar.

  • --argfile variable-name filename

不使用。改爲使用--slurpfile

(此選項類似於--slurpfile,但當文件只有一個文本時,則使用該文本,否則使用文本數組,如--slurpfile。)

  • --args

其餘參數是位置字符串參數。這些可用於 jq 程序作爲$ARGS.positional[].

  • --jsonargs

其餘參數是位置 JSON 文本參數。這些可用於 jq 程序作爲$ARGS.positional[].

  • --run-tests [filename]

在給定文件或標準輸入中運行測試。這必須是給出的最後一個選項,並且不支持所有前面的選項。輸入由註釋行、空行和程序行組成,後跟一個輸入行,與預期一樣多的輸出行(每個輸出一個),以及一個終止空行。編譯失敗測試從僅包含“%%FAIL”的行開始,然後是包含要編譯的程序的行,然後是包含要與實際進行比較的錯誤消息的行。

請注意,此選項可能會向後不兼容地更改。

基本過濾器

佔位符:.

絕對最簡單的過濾器是.. 這是一個過濾器,它接受其輸入並將其作爲輸出不變地產生。也就是說,這是佔位運算符。

由於 jq 默認情況下會漂亮地打印所有輸出,因此這個簡單的程序可以成爲格式化 JSON 輸出的有用方法,例如curl.

對象標識符索引:.foo.foo.bar

最簡單有用的過濾器是.foo. 當給定一個 JSON 對象(又名字典或哈希)作爲輸入時,它會在鍵“foo”處生成值,如果不存在則爲 null。

形式的過濾器.foo.bar等價於.foo|.bar

此語法僅適用於簡單的類似標識符的鍵,即全部由字母數字字符和下劃線組成且不以數字開頭的鍵。

如果鍵包含特殊字符或以數字開頭,則需要用雙引號將其括起來,例如: ."foo$"或 else .["foo$"]

例如.["foo::bar"]and .["foo.bar"]work while .foo::bardoesn't, and.foo.bar意味着.["foo"].["bar"]

可選對象標識符索引:.foo?

就像, 但在 不是數組或對象.foo時甚至不輸出錯誤。.

通用對象索引:.[<string>]

您還可以使用類似這樣的語法查找對象的字段 .["foo"](上面的 .foo 是它的簡寫版本,但僅適用於類似標識符的字符串)。

數組索引:.[2]

當索引值爲整數時,.[<value>]可以索引數組。數組從零開始,因此.[2]返回第三個元素。

允許使用負索引,-1 表示最後一個元素,-2 表示倒數第二個元素,依此類推。

數組/字符串切片:.[10:15]

.[10:15]語法可用於返回數組的子數組或字符串的子字符串。返回的數組 .[10:15]長度爲 5,包含從索引 10(包括)到索引 15(不包括)的元素。任何一個索引都可以是負數(在這種情況下,它從數組的末尾向後計數),或者被省略(在這種情況下,它指的是數組的開頭或結尾)。

數組/對象值迭代器:.[]

如果使用.[index]語法,但完全省略索引,它將返回數組的所有元素。.[]使用輸入運行[1,2,3]將產生三個單獨的結果,而不是單個數組。

您也可以在對象上使用它,它將返回對象的所有值。

.[]?

類似.[],但如果 . 則不會輸出錯誤。不是數組或對象。

逗號:,

如果兩個過濾器用逗號分隔,那麼相同的輸入將被饋送到兩個過濾器,兩個過濾器的輸出值流將按順序連接:首先,左表達式產生的所有輸出,然後是所有輸出由權利產生。例如, filter.foo, .bar生成“foo”字段和“bar”字段作爲單獨的輸出。

管道:|

該| 運算符通過將左側一個的輸出饋送到右側一個的輸入來組合兩個過濾器。如果您習慣的話,它與 Unix shell 的管道幾乎相同。

如果左邊的那個產生多個結果,那麼右邊的那個將爲每個結果運行。因此,表達式.[] | .foo檢索輸入數組的每個元素的“foo”字段。

請注意,.a.b.c與 相同.a | .b | .c

還要注意,這.是“管道”中特定階段的輸入值,特別是:.表達式出現的位置。因此.a | . | .b與 相同.a.b,因爲.中間的 指的是.a產生的任何值。

插入語

就像在任何典型的編程語言中一樣,括號作爲分組運算符工作。

類型和值

jq 支持與 JSON 相同的數據類型集 - 數字、字符串、布爾值、數組、對象(在 JSON 中是隻有字符串鍵的散列)和“null”。

布爾值、空值、字符串和數字的編寫方式與 javascript 相同。就像 jq 中的其他所有內容一樣,這些簡單的值接受一個輸入併產生一個輸出 -42是一個有效的 jq 表達式,它接受一個輸入,忽略它,並返回 42。

數組構造:[]

在 JSON 中,[]用於構造數組,如在 [1,2,3]. 數組的元素可以是任何 jq 表達式,包括管道。所有表達式產生的所有結果都收集到一個大數組中。您可以使用它從已知數量的值中構造一個數組(如[.foo, .bar, .baz])或將過濾器的所有結果“收集”到一個數組中(如[.items[].name]

一旦你理解了 "," 操作符,你就可以從不同的角度來看待 jq 的數組語法:表達式[1,2,3]沒有使用逗號分隔數組的內置語法,而是將[]操作符(收集結果)應用於表達式1,2,3(產生三種不同的結果)。

如果您有一個X產生四個結果的過濾器,那麼表達式[X]將產生一個結果,即一個由四個元素組成的數組。

對象構造:{}

像 JSON 一樣,{}用於構造對象(又名字典或哈希),如:{"a": 42, "b": 17}.

如果鍵是“類似標識符”,則可以省略引號,如{a:42, b:17}. 作爲鍵表達式的變量引用使用變量的值作爲鍵。常量文字、標識符或變量引用以外的關鍵表達式需要用括號括起來,例如 {("a"+"b"):59}.

該值可以是任何表達式(儘管您可能需要將其括在括號中,例如,如果它包含冒號),它將應用於 {} 表達式的輸入(請記住,所有過濾器都有一個輸入和一個輸出)。

{foo: .bar}

{"foo": 42}如果將 JSON 對象{"bar":42, "baz":43}作爲其輸入,將生成 JSON 對象。您可以使用它來選擇對象的特定字段:如果輸入是具有“user”、“title”、“id”和“content”字段的對象,而您只需要“user”和“title”,則可以寫

{user: .user, title: .title}

因爲這很常見,所以有一個快捷語法: {user, title}.

如果其中一個表達式產生多個結果,則將產生多個字典。如果輸入的

{"user":"stedolan","titles":["JQ Primer", "More JQ"]}

然後表達式

{user, title: .titles[]}

將產生兩個輸出:

{"user":"stedolan", "title": "JQ Primer"}
{"user":"stedolan", "title": "More JQ"}

在鍵周圍加上括號意味着它將被評估爲表達式。使用與上述相同的輸入,

{(.user): .titles}

輸出

{"stedolan": ["JQ Primer", "More JQ"]}

作爲鍵的變量引用使用變量的值作爲鍵。如果沒有值,則變量的名稱將成爲鍵,其值將成爲值,

"f o o" as $foo | "b a r" as $bar | {$foo, $bar:$foo}

輸出

{"f o o":"f o o","b a r":"f o o"}

遞歸下降:..

遞歸下降.,產生每個值。這與內置的零參數相同recurse(見下文)。這旨在類似於 XPath//運算符。注意 ..a不起作用;改爲使用..|.a。在下面的示例中,我們使用..|.a?在 "below" 找到的任何對象中查找對象鍵 "a" 的所有值.

這在與path(EXP) (另見下文)和?運算符結合使用時特別有用。

內置運算符和函數

一些 jq 運算符(例如+)根據其參數的類型(數組、數字等)執行不同的操作。但是, jq 從不進行隱式類型轉換。如果您嘗試將字符串添加到對象,您將收到一條錯誤消息並且沒有結果。

添加:+

運算符+採用兩個過濾器,將它們都應用於相同的輸入,然後將結果相加。“添加”的含義取決於所涉及的類型:

  • 數字是通過普通算術相加的。

  • 數組是通過連接成一個更大的數組來添加的。

  • 通過加入更大的字符串來添加字符串

  • 通過合併添加對象,即將兩個對象中的所有鍵值對插入到單個組合對象中。如果兩個對象都包含相同鍵的值,則右側的對象+獲勝。(對於遞歸合併,請使用*運算符。)

null可以添加到任何值,並返回其他值不變。

減法:-

除了對數字進行普通算術減法外,該- 運算符還可用於數組以從第一個數組中刪除第二個數組元素的所有出現。

乘法、除法、取模:*/, 和%

當給定兩個數字時,這些中綴運算符的行爲符合預期。除以零會引發錯誤。x % y計算 x 模 y。

將一個字符串乘以一個數字會產生多次串聯該字符串。"x" * 0產生null

將一個字符串除以另一個字符串會使用第二個字符串作爲分隔符來拆分第一個字符串。

將兩個對象相乘將遞歸合併它們:這類似於加法,但如果兩個對象都包含相同鍵的值,並且值是對象,則兩者將使用相同的策略合併。

length

內置函數length獲取各種不同類型值的長度:

  • 字符串的長度是它包含的 Unicode 代碼點的數量(如果它是純 ASCII,它將與它的 JSON 編碼長度(以字節爲單位)相同)。

  • 數組的長度是元素的數量。

  • 對象的長度是鍵值對的數量。

  • null的長度爲零。

utf8bytelength

內置函數utf8bytelength輸出用於以 UTF-8 編碼字符串的字節數。

keys,keys_unsorted

內置函數keys,當給定一個對象時,會在一個數組中返回它的鍵。

鍵按 unicode 代碼點順序“按字母順序”排序。這不是在任何特定語言中都特別有意義的順序,但您可以指望它對於具有相同鍵集的任何兩個對象都是相同的,而不管區域設置如何。

keys給定一個數組時,它返回該數組的有效索引:從 0 到 length-1 的整數。

keys_unsorted函數就像keys,但如果輸入是一個對象,那麼鍵將不會被排序,而是鍵將大致按插入順序排列。

has(key)

內置函數has返回輸入對象是否具有給定鍵,或者輸入數組在給定索引處是否具有元素。

has($key)$key 與檢查是否是由 返回的數組的成員具有相同的效果keys,但has 會更快。

in

內置函數in返回輸入鍵是否在給定對象中,或者輸入索引是否對應於給定數組中的元素。它本質上是has.

map(x),map_values(x)

對於任何 filter xmap(x)將爲輸入數組的每個元素運行該過濾器,並在新數組中返回輸出。map(.+1)將遞增數字數組的每個元素。

同樣,map_values(x)將爲每個元素運行該過濾器,但是當傳遞一個對象時它將返回一個對象。

map(x)相當於[.[] | x]。事實上,這就是它的定義方式。同樣,map_values(x)定義爲.[] |= x

path(path_expression)

輸出給定路徑表達式的數組表示形式.。輸出是字符串數組(對象鍵)和/或數字(數組索引)。

路徑表達式是 jq 表達式,例如.a, 也是.[]. 有兩種類型的路徑表達式:一種可以完全匹配,另一種不能。例如,.a.b.cis 是一個完全匹配的路徑表達式,while.a[].b不是。

path(exact_path_expression)將產生路徑表達式的數組表示,即使它不存在於., if .isnull或數組或對象中。

path(pattern)如果路徑pattern存在於..

請注意,路徑表達式與普通表達式沒有區別。該表達式 path(..|select(type=="boolean"))輸出 中布爾值的所有路徑.,並且僅輸出那些路徑。

del(path_expression)

內置函數del從對象中刪除鍵及其對應的值。

getpath(PATHS)

內置函數getpath輸出在 中.的每個路徑中找到的值PATHS

setpath(PATHS; VALUE)

內置函數setpathPATHSin設置.VALUE.

delpaths(PATHS)

內置函數delpaths設置PATHSin .。 PATHS必須是路徑數組,其中每個路徑都是字符串和數字的數組。

to_entriesfrom_entries,with_entries

這些函數在對象和鍵值對數組之間進行轉換。如果to_entries傳遞了一個對象,那麼對於k: v輸入中的每個條目,輸出數組包括{"key": k, "value": v}.

from_entries進行相反的轉換,並且 with_entries(foo)是 的簡寫to_entries | map(foo) | from_entries,用於對對象的所有鍵和值進行某些操作。from_entries接受鍵、鍵、名稱、名稱、值和值作爲鍵。

select(boolean_expression)

如果對該輸入返回 true,則該函數select(foo)將產生其輸入不變 foo,否則不產生任何輸出。

它對過濾列表很有用:[1,2,3] | map(select(. >= 2)) 會給你[2,3].

arraysobjectsiterablesbooleansnumbersnormalsfinitesstringsnullsvalues,scalars

這些內置函數分別只選擇數組、對象、可迭代對象(數組或對象)、布爾值、數字、普通數、有限數、字符串、空值、非空值和非可迭代值的輸入。

empty

empty不返回任何結果。一個都沒有。甚至沒有null

有時它很有用。你會知道你是否需要它:)

error(message)

產生錯誤,就像.a應用於 null 和對象以外的值一樣,但將給定的消息作爲錯誤的值。可以使用 try/catch 捕獲錯誤;見下文。

halt

停止 jq 程序,不再輸出。jq 將以退出狀態退出0

halt_error,halt_error(exit_code)

停止 jq 程序,不再輸出。輸入將stderr作爲原始輸出(即字符串沒有雙引號)打印,沒有任何裝飾,甚至沒有換行符。

給定的exit_code(默認爲5)將是 jq 的退出狀態。

例如,"Error: somthing went wrong\n"|halt_error(1)

$__loc__

生成一個帶有“file”鍵和“line”鍵的對象,其中$__loc__出現的文件名和行號作爲值。

pathspaths(node_filter),leaf_paths

paths輸出其輸入中所有元素的路徑(除了它不輸出空列表,表示 . 本身)。

paths(f)輸出任何f爲真值的路徑。也就是說,paths(numbers)輸出所有數值的路徑。

leaf_pathspaths(scalars);的別名 leaf_paths已 棄用,將在下一個主要版本中刪除。

add

過濾器add將一個數組作爲輸入,並將數組的元素加在一起作爲輸出。這可能意味着求和、連接或合併,具體取決於輸入數組元素的類型 - 規則與運算符的規則相同+(如上所述)。

如果輸入是空數組,則add返回null

anyany(condition),any(generator; condition)

過濾器any將布爾值數組作爲輸入,true如果數組的任何元素爲 ,則將其作爲輸出true

如果輸入是空數組,則any返回false

any(condition)表單將給定條件應用於輸入數組的元素。

any(generator; condition)表格將給定條件應用於給定生成器的所有輸出。

allall(condition),all(generator; condition)

過濾器all將一個布爾值數組作爲輸入,true如果數組的所有元素都是 ,則將其作爲輸出true

all(condition)表單將給定條件應用於輸入數組的元素。

all(generator; condition)表格將給定條件應用於給定生成器的所有輸出。

如果輸入是空數組,則all返回true

flatten,flatten(depth)

過濾器flatten將嵌套數組的數組作爲輸入,並生成一個平面數組,其中原始數組中的所有數組都已被其值遞歸替換。您可以將參數傳遞給它以指定要展平的嵌套級別。

flatten(2)就像flatten,但只有兩個級別的深度。

range(upto),range(from;upto) range(from;upto;by)

range函數產生一系列數字。range(4;10) 產生 6 個數字,從 4(包括)到 10(不包括)。這些數字作爲單獨的輸出產生。用於[range(4;10)]將範圍作爲數組獲取。

one 參數形式生成從 0 到給定數字的數字,增量爲 1。

兩個參數形式生成從fromupto 以 1 爲增量的數字。

三自變量形式生成fromupto 爲增量的數字by

floor

floor函數返回其數字輸入的下限。

sqrt

sqrt函數返回其數字輸入的平方根。

tonumber

tonumber函數將其輸入解析爲數字。它會將格式正確的字符串轉換爲等效的數字,不理會數字,並在所有其他輸入上出錯。

tostring

tostring函數將其輸入打印爲字符串。字符串保持不變,所有其他值都是 JSON 編碼的。

type

type函數將其參數的類型作爲字符串返回,它是 null、布爾值、數字、字符串、數組或對象之一。

infinitenanisinfiniteisnanisfinite,isnormal

一些算術運算可以產生無窮大和“非數字”(NaN)值。 如果其輸入是無限的,則isinfinite內置函數返回。true如果其 輸入是 NaN ,則isnan內置函數返回。內置函數返回一個正無窮大值true。內置函數返回一個 NaN infinitenan如果其isnormal輸入是正常數字,則內置函數返回 true。

請注意,除以零會引發錯誤。

目前,大多數在無窮大、NaN 和次正規數上進行的算術運算都不會引發錯誤。

sort, sort_by(path_expression)

這些sort函數對其輸入進行排序,該輸入必須是一個數組。值按以下順序排序:

  • null
  • false
  • true
  • 數字
  • 字符串,按字母順序(按 unicode 代碼點值)
  • 數組,按詞法順序
  • 對象

對象的排序有點複雜:首先通過比較它們的鍵集(作爲排序順序的數組)來比較它們,如果它們的鍵相等,則逐個鍵比較值。

sort可用於按對象的特定字段或應用任何 jq 過濾器進行排序。

sort_by(foo)通過比較每個元素的結果來比較兩個元素 foo

group_by(path_expression)

group_by(.foo)將數組作爲輸入,將具有相同.foo字段的元素分組到單獨的數組中,並將所有這些數組生成爲更大數組的元素,並按.foo字段的值排序。

任何 jq 表達式,不僅僅是一個字段訪問,都可以用來代替.foosort排序順序與上面函數中描述的相同。

minmaxmin_by(path_exp),max_by(path_exp)

查找輸入數組的最小或最大元素。

和函數允許您指定要檢查的特定字段或屬性,例如 min_by(path_exp)查找具有最小字段的對象。max_by(path_exp)min_by(.foo)foo

unique,unique_by(path_exp)

unique函數將一個數組作爲輸入,並按排序順序生成一個包含相同元素的數組,並刪除重複項。

對於通過應用參數獲得的每個值,該unique_by(path_exp)函數將只保留一個元素。可以將其視爲通過從group.

reverse

此函數反轉數組。

contains(element)

contains(b)如果 b 完全包含在輸入中,則過濾器將產生 true。如果 B 是 A 的子字符串,則字符串 B 包含在字符串 A 中。如果 B 中的所有元素都包含在 A 中的任何元素中,則數組 B 包含在數組 A 中。如果所有元素都包含在對象 B 中,則對象 B 包含在對象 A 中B 中的值包含在具有相同鍵的 A 中的值中。如果所有其他類型相等,則假定它們相互包含。

indices(s)

輸出一個數組,其中包含.where的索引s 。輸入可能是一個數組,在這種情況下,如果s是一個數組,那麼索引輸出將是所有元素.匹配的那些s

index(s),rindex(s)

index輸出輸入中第一個 ( ) 或最後一個 ( rindex) 出現的索引s

inside

inside(b)如果輸入完全包含在 b 中,則過濾器將產生 true。它本質上是contains.

startswith(str)

輸出true如果。從給定的字符串參數開始。

endswith(str)

輸出true如果。以給定的字符串參數結束。

combinations,combinations(n)

輸出輸入數組中數組元素的所有組合。如果給定一個參數n,它會輸出n輸入數組的所有重複組合。

ltrimstr(str)

如果它以它開頭,則輸出它的輸入並刪除給定的前綴字符串。

rtrimstr(str)

如果它以它結尾,則輸出它的輸入並刪除給定的後綴字符串。

explode

將輸入字符串轉換爲字符串代碼點編號的數組。

implode

爆炸的反面。

split(str)

在分隔符參數上拆分輸入字符串。

join(str)

使用參數作爲分隔符連接作爲輸入給定的元素數組。它是split: 的倒數,也就是說,split("foo") | join("foo")在任何輸入字符串上運行都會返回所述輸入字符串。

輸入中的數字和布爾值被轉換爲字符串。Null 值被視爲空字符串。不支持輸入中的數組和對象。

ascii_downcase,ascii_upcase

發出輸入字符串的副本,並將其字母字符(az 和 AZ)轉換爲指定的大小寫。

while(cond; update)

while(cond; update)功能允許您重複應用更新,.直到cond爲假。

請注意,它while(cond; update)在內部定義爲遞歸 jq 函數。如果每個輸入最多產生一個輸出,則內部的遞歸調用while不會消耗額外的內存。update請參閱下面的高級主題。

until(cond; next)

until(cond; next)函數允許您重複應用表達式next,從最初到.然後到它自己的輸出,直到cond爲真。例如,這可用於實現階乘函數(見下文)。

請注意,它until(cond; next)在內部定義爲遞歸 jq 函數。如果每個輸入最多產生一個輸出,則內部的遞歸調用until()不會消耗額外的內存。next請參閱下面的高級主題。

recurse(f)recurserecurse(f; condition),recurse_down

recurse(f)功能允許您搜索遞歸結構,並從各個級別提取有趣的數據。假設您的輸入代表一個文件系統:

{"name": "/", "children": [
  {"name": "/bin", "children": [
    {"name": "/bin/ls", "children": []},
    {"name": "/bin/sh", "children": []}]},
  {"name": "/home", "children": [
    {"name": "/home/stephen", "children": [
      {"name": "/home/stephen/jq", "children": []}]}]}]}

現在假設您要提取所有存在的文件名。您需要檢索.name.children[].name、 .children[].children[].name等。你可以這樣做:

recurse(.children[]) | .name

不帶參數調用時,recurse等效於 recurse(.[]?).

recurse(f)與遞歸深度相同recurse(f; . != null),可以在不考慮遞歸深度的情況下使用。

recurse(f; condition)是一個以發射 開始的生成器。然後依次發出 .|f, .|f|f, .|f|f|f, ... 只要計算值滿足條件。例如,要生成所有整數,至少原則上可以寫成recurse(.+1; true).

由於遺留原因,作爲不帶參數recurse_down調用的別名存在。recurse此別名已被 棄用,將在下一個主要版本中刪除。

只要每個輸入最多產生一個輸出,遞歸調用recurse就不會消耗額外的內存。f

walk(f)

walk(f)函數遞歸地應用於輸入實體的每個組件。當遇到一個數組時,f首先應用於其元素,然後應用於數組本身;當遇到一個對象時,首先將 f 應用於所有值,然後再應用於該對象。在實踐中,f 通常會測試其輸入的類型,如下面的示例所示。第一個示例強調了在處理數組本身之前處理數組元素的有用性。第二個示例顯示瞭如何考慮更改輸入中所有對象的所有鍵。

$ENV,env

$ENV是一個對象,表示 jq 程序啓動時設置的環境變量。

env輸出一個代表 jq 當前環境的對象。

目前沒有用於設置環境變量的內置函數。

transpose

轉置一個可能鋸齒狀的矩陣(數組的數組)。行用空值填充,因此結果始終爲矩形。

bsearch(x)

bsearch(x) 在輸入數組中對 x 進行二分搜索。如果輸入已排序幷包含 x,則 bsearch(x) 將返回其在數組中的索引;否則,如果數組已排序,它將返回 (-1 - ix),其中 ix 是一個插入點,因此在將 x 插入到 ix 後,該數組仍將被排序。如果數組未排序,bsearch(x) 將返回一個可能不感興趣的整數。

字符串插值 -\(foo)

在字符串中,您可以在反斜槓後的括號內放置表達式。無論表達式返回什麼,都將被插入到字符串中。

轉換爲/從 JSON

tojson和builtins 分別將值轉儲爲 JSON 文本或將fromjsonJSON 文本解析爲值。內置 tojson 與 tostring 的不同之處在於 tostring 返回未修改的字符串,而 tojson 將字符串編碼爲 JSON 字符串。

格式化字符串和轉義

@foo語法用於格式化和轉義字符串,這對於構建 URL、HTML 或 XML 等語言的文檔等很有用。@foo可以單獨用作過濾器,可能的轉義是:

  • @text

調用tostring,請參閱該函數以獲取詳細信息。

  • @json

將輸入序列化爲 JSON。

  • @html

通過將字符映射 <>&'"到它們的實體等價物&lt;&gt;&amp;&apos;,來應用 HTML/XML 轉義&quot;

  • @uri

通過將所有保留的 URI 字符映射到一個%XX序列來應用百分比編碼。

  • @csv

輸入必須是一個數組,並將其呈現爲 CSV,字符串帶有雙引號,引號通過重複轉義。

  • @tsv

輸入必須是一個數組,並且呈現爲 TSV(製表符分隔值)。每個輸入數組將打印爲一行。字段由單個選項卡 (ascii 0x09) 分隔。輸入字符換行 (ascii 0x0a)、回車 (ascii 0x0d)、製表符 (ascii 0x09) 和反斜槓 (ascii 0x5c) 將分別輸出爲轉義 序列\n\r, 。\t\\

  • @sh

輸入經過轉義,適合在 POSIX shell 的命令行中使用。如果輸入是數組,則輸出將是一系列以空格分隔的字符串。

  • @base64

輸入將轉換爲 RFC 4648 指定的 base64。

  • @base64d

, 的逆@base64輸入按照 RFC 4648 的規定進行解碼。 注意\:如果解碼的字符串不是 UTF-8,則結果未定義。

這種語法可以以一種有用的方式與字符串插值相結合。您可以在@foo標記後面加上字符串文字。字符串文字的內容不會被轉義。但是,在該字符串文字內進行的所有插值都將被轉義。例如,

@uri "https://www.google.com/search?q=\(.search)"

將爲輸入產生以下輸出 {"search":"what is jq?"}

"https://www.google.com/search?q=what%20is%20jq%3F"

請注意,URL 中的斜槓、問號等不會被轉義,因爲它們是字符串文字的一部分。

日期

jq 提供了一些基本的日期處理功能,以及一些高級和低級的內置函數。在所有情況下,這些內置函數都專門處理 UTC 時間。

內置函數將 ISO 8601 格式的fromdateiso8601日期時間解析爲自 Unix 紀元 (1970-01-01T00:00:00Z) 以來的秒數。todateiso8601內置執行相反的操作。

fromdate內置解析日期時間字符串。目前 fromdate僅支持 ISO 8601 日期時間字符串,但未來它將嘗試解析更多格式的日期時間字符串。

內置函數todate是.todateiso8601

now內置輸出當前時間,以 Unix 紀元以來的秒數爲單位。

還提供了 C 庫時間函數的低級 jq 接口:strptimestrftimestrflocaltime、 mktimegmtimelocaltimestrptime有關和使用的格式字符串,請參閱主機操作系統的文檔strftime。注意:這些不一定是 jq 中的穩定接口,尤其是它們的本地化功能。

內置函數消耗自 Unix 紀元以來的gmtime秒數,並輸出 Greenwhich Meridian 時間的“分解時間”表示,作爲表示(按此順序)的數字數組:年、月(從零開始)、日期月份(從 1 開始)、一天中的小時、小時中的分鐘、分鐘中的秒、一週中的一天和一年中的一天——除非另有說明,否則都是從 1 開始的。對於 1900 年 3 月 1 日之前或 2099 年 12 月 31 日之後的日期,某些系統上的星期數可能是錯誤的。

內置函數的localtime工作方式與gmtime內置函數類似,但使用本地時區設置。

內置使用和輸出的時間的mktime“分解時間”表示。gmtimestrptime

內置解析與參數匹配的strptime(fmt)輸入字符串 fmtgmtime輸出是由 消耗和輸出的“分解時間”表示mktime

內置使用strftime(fmt)給定格式格式化時間(GMT)。執行strflocaltime相同的操作,但使用本地時區設置。

strptime和的格式字符串strftime在典型的 C 庫文檔中進行了描述。ISO 8601 日期時間的格式字符串是"%Y-%m-%dT%H:%M:%SZ".

jq 在某些系統上可能不支持部分或全部此日期功能。特別是,macOS 不支持%uand%j說明符 。strptime(fmt)

SQL 風格的運算符

jq 提供了一些 SQL 風格的運算符。

  • 索引(流;索引表達式):

此內置函數生成一個對象,其鍵由應用於給定流中每個值的給定索引表達式計算。

  • 加入($idx;流;idx_expr;join_expr):

此內置函數將給定流中的值連接到給定索引。通過將給定的索引表達式應用於給定流中的每個值來計算索引的鍵。流中的值和索引中的相應值的數組被饋送到給定的連接表達式以產生每個結果。

  • 加入($idx;流;idx_expr):

與 相同JOIN($idx; stream; idx_expr; .)

  • 加入($idx;idx_expr):

這個內置函數將輸入連接.到給定的索引,應用給定的索引表達式.來計算索引鍵。加入操作如上所述。

  • 輸入:

true如果出現在給定的流中,則此內置輸出.,否則輸出false

  • IN(來源;S):

如果源流中的任何值出現在第二個流中,則此內置輸出true,否則輸出false

builtins

返回格式爲 的所有內置函數的列表name/arity。由於具有相同名稱但不同數量的函數被認爲是單獨的函數,因此all/0,all/1all/2都將出現在列表中。

條件和比較

==,!=

如果 a 和 b 的結果相等(即,如果它們表示等效的 JSON 文檔),則表達式 'a == b' 將產生 'true',否則將產生 'false'。特別是,字符串永遠不會被視爲等於數字。如果您來自 Javascript,jq 的 == 就像 Javascript 的 === - 僅當它們具有相同類型和相同值時才考慮值相等。

!= 是“不等於”,'a != b' 返回 'a == b' 的相反值

如果-那麼-否則

if A then B else C end將與 產生除 false 或 null 以外的值相同,但與B其他情況相同。AC

if A then B end是一樣的if A then B else . end。也就是說,else分支是可選的,如果不存在則與..

檢查 false 或 null 是比 Javascript 或 Python 中更簡單的“真實性”概念,但這意味着您有時必須更明確地瞭解您想要的條件。您無法測試,例如,字符串是否爲空使用if .name then A else B end,您將需要更多類似的東西if .name then A else B end

如果條件A產生多個結果,則B對每個不爲 false 或 null 的結果C評估一次,併爲每個 false 或 null 評估一次。

更多情況可以添加到 if 使用elif A then B語法。

>, >=, <=, <

比較運算符>>=<=,<分別返回其左參數是否大於、大於或等於、小於或等於或小於其右參數。

順序與上面描述的相同sort

和/或/不是

jq 支持普通的布爾運算符和/或/非。它們與 if 表達式具有相同的真實標準 - false 和 null 被認爲是“假值”,而其他任何東西都是“真值”。

如果這些運算符之一的操作數產生多個結果,則運算符本身將爲每個輸入產生一個結果。

not實際上是一個內置函數而不是一個運算符,因此它被稱爲過濾器,可以將事物通過管道傳遞給它,而不是使用特殊語法,如.foo and .bar | not.

這三個只產生值“true”和“false”,因此只對真正的布爾運算有用,而不是常見的 Perl/Python/Ruby 習語“value_that_may_be_null or default”。如果您想使用這種形式的“或”,在兩個值之間進行選擇而不是評估條件,請參閱下面的“//”運算符。

替代運算符://

形式的過濾器a // b產生與 相同的結果a,如果a產生 和 以外false 的結果null。否則,a // b產生與 相同的結果b

這對於提供默認值很有用:如果輸入中沒有元素,.foo // 1將評估爲。它類似於Python 中有時使用的方式(jq 的運算符保留用於嚴格的布爾運算)。1.foooror

試着抓

可以使用 捕獲錯誤try EXP catch EXP。執行第一個表達式,如果失敗,則執行第二個表達式並顯示錯誤消息。處理程序的輸出(如果有)的輸出就像它是要嘗試的表達式的輸出一樣。

try EXP表單empty用作異常處理程序。

中斷控制結構

try/catch 的一個方便使用是打破控制結構,如reduceforeachwhile, 等等。

例如:

# Repeat an expression until it raises "break" as an
# error, then stop repeating without re-raising the error.
# But if the error caught is not "break" then re-raise it.
try repeat(exp) catch .=="break" then empty else error;

jq 有一個命名詞法標籤的語法來“break”或“go (back) to”:

label $out | ... break $out ...

break $label_name表達式將使程序表現得好像最近(向左)label $label_name 產生了empty.

break和對應之間的關係label 是詞法的:標籤必須從中斷處“可見”。

突破一個reduce,例如:

label $out | reduce .[] as $item (null; if .==false then break $out else ... end)

以下 jq 程序產生語法錯誤:

break $out

因爲沒有標籤$out可見。

錯誤抑制/可選運算符:?

?用作的運算符EXP?是 的簡寫try EXP

正則表達式 (PCRE)

jq 使用 Oniguruma 正則表達式庫,php、ruby、TextMate、Sublime Text 等也是如此,所以這裏的描述將集中在 jq 的細節上。

定義了 jq 正則表達式過濾器,以便可以使用以下模式之一使用它們:

STRING | FILTER( REGEX )
STRING | FILTER( REGEX; FLAGS )
STRING | FILTER( [REGEX] )
STRING | FILTER( [REGEX, FLAGS] )

在哪裏:

  • STRING、REGEX 和 FLAGS 是 jq 字符串,需要進行 jq 字符串插值;
  • REGEX,在字符串插值之後,應該是一個有效的 PCRE 正則表達式;
  • FILTER 是、 或之一test,如下所述。matchcapture

FLAGS 是一個字符串,由多個受支持的標誌之一組成:

  • g- 全局搜索(查找所有匹配項,而不僅僅是第一個)
  • i- 不區分大小寫的搜索
  • m- 多行模式('.' 將匹配換行符)
  • n- 忽略空匹配
  • p- 啓用 s 和 m 模式
  • s- 單行模式 ('^' -> '\A', '$' -> '\Z')
  • l- 找到最長的匹配
  • x- 擴展正則表達式格式(忽略空格和註釋)

要匹配 x 模式中的空格,請使用轉義符,例如 \s,例如

  • 測試(“a\sb”,“x”)。

請注意,某些標誌也可以在 REGEX 中指定,例如

  • jq -n '(“測試”,“測試”,“測試”,“測試”)| 測試(“(?i)te(?-i)st”)'

計算結果爲:真、真、假、假。

test(val),test(regex; flags)

Like match,但不返回匹配對象,僅返回正則表達式true是否false 匹配輸入。

match(val),match(regex; flags)

match爲它找到的每個匹配輸出一個對象。匹配具有以下字段:

  • offset- UTF-8 代碼點與輸入開頭的偏移量
  • length- 匹配的 UTF-8 代碼點長度
  • string- 它匹配的字符串
  • captures- 代表捕獲組的對象數組。

捕獲組對象具有以下字段:

  • offset- UTF-8 代碼點與輸入開頭的偏移量
  • length- 此捕獲組的 UTF-8 代碼點長度
  • string- 被捕獲的字符串
  • name- 捕獲組的名稱(或者null如果它未命名)

捕獲不匹配任何內容的組會返回 -1 的偏移量

capture(val),capture(regex; flags)

在 JSON 對象中收集命名的捕獲,每個捕獲的名稱作爲鍵,匹配的字符串作爲對應的值。

scan(regex),scan(regex; flags)

根據標誌(如果已指定)發出與正則表達式匹配的輸入的非重疊子串流。如果沒有匹配,則流爲空。要捕獲每個輸入字符串的所有匹配項,請使用成語 [ expr ],例如[ scan(regex) ].

split(regex; flags)

爲了向後兼容,split拆分字符串,而不是正則表達式。

splits(regex),splits(regex; flags)

它們提供與它們的對應物相同的結果split,但作爲流而不是數組。

sub(regex; tostring) sub(regex; string; flags)

將輸入字符串中正則表達式的第一個匹配項替換爲tostring, 插值後,發出字符串。 tostring應該是一個 jq 字符串,並且可能包含對命名捕獲的引用。命名的捕獲實際上是作爲 JSON 對象(由 構造的capture)呈現給 的tostring,因此對名爲“x”的捕獲變量的引用將採用以下形式:“(.x)”。

gsub(regex; string),gsub(regex; string; flags)

gsub就像sub但是在插值之後,正則表達式的所有非重疊出現都被字符串替換。

高級功能

變量在大多數編程語言中是絕對必要的,但它們在 jq 中被歸爲“高級特性”。

在大多數語言中,變量是傳遞數據的唯一方式。如果你計算一個值,並且你想多次使用它,你需要將它存儲在一個變量中。要將值傳遞給程序的另一部分,您需要程序的該部分定義一個變量(作爲函數參數、對象成員或其他)來放置數據。

也可以在 jq 中定義函數,儘管這是一個最大用途是定義 jq 的標準庫的功能(許多 jq 函數,例如mapfind實際上是用 jq 編寫的)。

jq 有歸約運算符,它們非常強大但有點棘手。同樣,這些主要在內部使用,以定義 jq 標準庫的一些有用位。

一開始可能並不明顯,但 jq 是關於生成器的(是的,這在其他語言中很常見)。提供了一些實用程序來幫助處理生成器。

一些最小的 I/O 支持(除了從標準輸入讀取 JSON 並將 JSON 寫入標準輸出)是可用的。

最後,還有一個模塊/庫系統。

變量/符號綁定運算符:... as $identifier | ...

在 jq 中,所有過濾器都有一個輸入和一個輸出,因此不需要手動管道將值從程序的一個部分傳遞到下一個部分。許多表達式,例如a + b,將它們的輸入傳遞給兩個不同的子表達式(這裏ab都傳遞相同的輸入),因此通常不需要使用變量來兩次使用一個值。

例如,在大多數語言中,計算一個數字數組的平均值需要一些變量——至少有一個變量來保存數組,可能每個元素或循環計數器都有一個變量。在 jq 中,它很簡單add / length-add表達式被賦予數組併產生其總和,length表達式被賦予數組併產生其長度。

因此,通常有一種比定義變量更簡潔的方法來解決 jq 中的大多數問題。儘管如此,有時它們確實使事情變得更容易,因此 jq 允許您使用expression as $variable. 所有變量名都以$. 這是數組平均示例的一個稍微醜陋的版本:

length as $array_length | add / $array_length

我們需要一個更復雜的問題來找到使用變量實際上使我們的生活更輕鬆的情況。

假設我們有一個博客文章數組,其中包含“作者”和“標題”字段,以及另一個用於將作者用戶名映射到真實姓名的對象。我們的輸入看起來像:

{"posts": [{"title": "Frist psot", "author": "anon"},
           {"title": "A well-written article", "author": "person1"}],
 "realnames": {"anon": "Anonymous Coward",
               "person1": "Person McPherson"}}

我們希望生成包含真實姓名的作者字段的帖子,如下所示:

{"title": "Frist psot", "author": "Anonymous Coward"}
{"title": "A well-written article", "author": "Person McPherson"}

我們使用變量 $names 來存儲 realnames 對象,以便稍後在查找作者用戶名時引用它:

.realnames as $names | .posts[] | {title, author: $names[.author]}

表達式exp as $x | ...意味着:對於表達式的每個值, exp使用整個原始輸入運行管道的其餘部分,並$x設置爲該值。因此as起到某種 foreach 循環的作用。

就像{foo}方便的寫作方式一樣,方便的寫作方式也是{foo: .foo}如此 。{$foo}{foo:$foo}

as通過提供與輸入結構匹配的模式(這稱爲“解構”),可以使用單個表達式聲明多個變量:

. as {realnames: $names, posts: [$first, $second]} | ...

數組模式中的變量聲明(例如,. as [$first, $second])按順序綁定到數組的元素,從索引零的元素開始。當數組模式元素的索引處沒有值時,null將綁定到該變量。

變量的範圍在定義它們的表達式的其餘部分,所以

.realnames as $names | (.posts[] | {title, author: $names[.author]})

會工作,但是

(.realnames as $names | .posts[]) | {title, author: $names[.author]}

慣於。

對於編程語言理論家來說,更準確的說法是 jq 變量是詞法範圍的綁定。特別是沒有辦法改變綁定的值;只能設置一個具有相同名稱的新綁定,但在舊綁定的位置不可見。

解構替代運算符:?//

解構替代運算符提供了一種簡潔的機制來解構可以採用多種形式之一的輸入。

假設我們有一個 API,它返回一個資源列表和與之關聯的事件,我們想要獲取每個資源的第一個事件的 user_id 和時間戳。如果資源有多個事件,API(已經笨拙地從 XML 轉換)只會將事件包裝在數組中:

{"resources": [{"id": 1, "kind": "widget", "events": {"action": "create", "user_id": 1, "ts": 13}},
               {"id": 2, "kind": "widget", "events": [{"action": "create", "user_id": 1, "ts": 14}, {"action": "destroy", "user_id": 1, "ts": 15}]}]}

我們可以使用解構替代運算符來簡單地處理這種結構變化:

.resources[] as {$id, $kind, events: {$user_id, $ts}} ?// {$id, $kind, events: [{$user_id, $ts}]} | {$user_id, $kind, $id, $ts}

或者,如果我們不確定輸入是值數組還是對象:

.[] as [$id, $kind, $user_id, $ts] ?// {$id, $kind, $user_id, $ts} | ...

每個備選方案不需要定義所有相同的變量,但所有命名變量都可用於後續表達式。在成功的替代方案中不匹配的變量將是null

.resources[] as {$id, $kind, events: {$user_id, $ts}} ?// {$id, $kind, events: [{$first_user_id, $first_ts}]} | {$user_id, $first_user_id, $kind, $id, $ts, $first_ts}

此外,如果後續表達式返回錯誤,則替代運算符將嘗試嘗試下一個綁定。在最終替代過程中發生的錯誤將被傳遞。

[[3]] | .[] as [$a] ?// [$b] | if $a != null then error("err: \($a)") else {$a,$b} end

定義函數

您可以使用“def”語法爲過濾器命名:

def increment: . + 1;

從那時起,increment就可以像內置函數一樣用作過濾器(實際上,這就是定義了多少個內置函數)。函數可以接受參數:

def map(f): [.[] | f];

參數作爲過濾器(沒有參數的函數)傳遞,而不是作爲值傳遞。可以使用不同的輸入多次引用相同的參數(這裏f針對輸入數組的每個元素運行)。函數的參數更像回調而不是值參數。理解這一點很重要。考慮:

def foo(f): f|f;
5|foo(.*2)

結果將是 20,因爲fis .*2,並且在第一次調用f .將是 5,第二次將是 10 (5 * 2),所以結果將是 20。函數參數是過濾器,過濾器期望輸入調用。

如果你想要定義簡單函數的值參數行爲,你可以只使用一個變量:

def addvalue(f): f as $f | map(. + $f);

或者使用簡寫:

def addvalue($f): ...;

無論使用哪種定義,addvalue(.foo)都會將當前輸入的.foo字段添加到數組的每個元素中。請注意,調用addvalue(.[])將導致在調用站點map(. + $f)的值中的每個值對部件進行一次評估。.

允許使用相同函數名的多個定義。對於相同數量的函數參數,每個重新定義都會替換先前的重新定義,但僅適用於重新定義之後的函數(或主程序)的引用。另請參閱下面有關範圍界定的部分。

範圍界定

jq 中有兩種類型的符號:值綁定(又名“變量”)和函數。兩者都是詞法範圍的,表達式只能引用已在它們“左側”定義的符號。該規則的唯一例外是函數可以引用自身以便能夠創建遞歸函數。

例如,在下面的表達式中,有一個綁定在它的“右側”可見... | .*3 as $times_three | [. + $times_three] | ...,但在“左側”不可見。現在考慮這個表達式... | (.*3 as $times_three | [. + $times_three]) | ...:這裏的綁定 在右括號之後$times_three可見的。

減少

jq 中的reduce語法允許您通過將表達式的所有結果累積成一個答案來組合它們。例如,我們將傳遞[3,2,1]給這個表達式:

reduce .[] as $item (0; . + $item)

對於.[]產生的每個結果,. + $item運行以累積從 0 開始的運行總計。在此示例中,.[]產生結果 3、2 和 1,因此效果類似於運行以下內容:

0 | (3 as $item | . + $item) |
    (2 as $item | . + $item) |
    (1 as $item | . + $item)

isempty(exp)

exp如果不產生輸出,則返回 true ,否則返回 false。

limit(n; exp)

limit函數最多從 中提取n輸出exp

first(expr)last(expr),nth(n; expr)

first(expr)和函數分別從中last(expr)提取第一個和最後一個值expr

nth(n; expr)函數提取由 輸出的第 n 個值 expr。這可以定義爲def nth(n; expr): last(limit(n + 1; expr));。請注意,nth(n; expr)不支持n.

firstlast,nth(n)

firstand函數從位於的last任何數組中提取第一個和最後一個值.

nth(n)函數在 處提取任何數組的第 n 個值.

foreach

foreach語法類似於reduce,但旨在允許構造limit和生成中間結果的化簡器(參見示例)。

形式是foreach EXP as $var (INIT; UPDATE; EXTRACT)。像reduce,INIT被評估一次以產生一個狀態值,然後每個輸出EXP綁定到$var,UPDATE 被評估爲EXP具有當前狀態和$var可見的每個輸出。輸出的每個值都會UPDATE 替換先前的狀態。最後,EXTRACT對每個新狀態進行評估以提取 的輸出foreach

這僅對構造reduce- 和 - limit類似的函數非常有用。但它更通用,因爲它允許部分減少(參見下面的示例)。

遞歸

如上所述,recurse使用遞歸,任何jq函數都可以遞歸。while內置函數也以遞歸的方式實現。

只要遞歸調用左側的表達式輸出其最後一個值,就會優化尾調用。實際上,這意味着遞歸調用左側的表達式不應爲每個輸入生成多個輸出。

例如:

def recurse(f): def r: ., (f | select(. != null) | r); r;

def while(cond; update):
  def _while:
    if cond then ., (update | _while) else empty end;
  _while;

def repeat(exp):
  def _repeat:
    exp, _repeat;
  _repeat;

生成器和迭代器

一些 jq 運算符和函數實際上是生成器,因爲它們可以爲每個輸入生成零、一個或多個值,正如人們在其他具有生成器的編程語言中所期望的那樣。例如,.[] 生成其輸入中的所有值(必須是數組或對象),range(0; 10)生成 0 到 10 之間的整數,等等。

甚至逗號運算符也是一個生成器,它首先生成由逗號左側的表達式生成的值,然後對於其中的每一個,生成由逗號右側的表達式生成的值。

empty內置是產生零輸出的生成器。empty內置回溯到前面的生成器表達式。

All jq functions can be generators just by using builtin generators. It is also possible to define new generators using only recursion and the comma operator. If the recursive call(s) is(are) "in tail position" then the generator will be efficient. In the example below the recursive call by _range to itself is in tail position. The example shows off three advanced topics: tail recursion, generator construction, and sub-functions.

Math

jq currently only has IEEE754 double-precision (64-bit) floating point number support.

Besides simple arithmetic operators such as +, jq also has most standard math functions from the C math library. C math functions that take a single input argument (e.g., sin()) are available as zero-argument jq functions. C math functions that take two input arguments (e.g., pow()) are available as two-argument jq functions that ignore .. C math functions that take three input arguments are available as three-argument jq functions that ignore ..

Availability of standard math functions depends on the availability of the corresponding math functions in your operating system and C math library. Unavailable math functions will be defined but will raise an error.

One-input C math functions: acos acosh asin asinh atan atanh cbrt ceil cos cosh erf erfc exp exp10 exp2 expm1 fabs floor gamma j0 j1 lgamma log log10 log1p log2 logb nearbyint pow10 rint round significand sin sinh sqrt tan tanh tgamma trunc y0 y1.

Two-input C math functions: atan2 copysign drem fdim fmax fmin fmod frexp hypot jn ldexp modf nextafter nexttoward pow remainder scalb scalbln yn.

Three-input C math functions: fma.

See your system's manual for more information on each of these.

I/O

At this time jq has minimal support for I/O, mostly in the form of control over when inputs are read. Two builtins functions are provided for this, input and inputs, that read from the same sources (e.g., stdin, files named on the command-line) as jq itself. These two builtins, and jq's own reading actions, can be interleaved with each other.

兩個內置函數提供最小的輸出功能debug, 和 stderr. (回想一下,jq 程序的輸出值總是作爲 JSON 文本輸出到stdout.)debug內置可以具有特定於應用程序的行爲,例如對於使用 libjq C API 但不是 jq 可執行文件本身的可執行文件。內置將stderr 其輸入以原始模式輸出到 stder,沒有額外的裝飾,甚至沒有換行符。

大多數 jq 內置函數在引用上是透明的,並且在應用於常量輸入時會產生常量和可重複的值流。這不適用於 I/O 內置函數。

input

輸出一個新的輸入。

inputs

一個一個地輸出所有剩餘的輸入。

這主要用於減少程序的輸入。

debug

產生基於輸入值的調試消息。jq 可執行文件用輸入值包裝 ["DEBUG:", <input-value>]並在 stderr 上緊湊地打印該值和換行符。這在未來可能會改變。

stderr

以原始和緊湊模式將其輸入打印到 stderr,沒有額外的裝飾,甚至沒有換行符。

input_filename

返回當前正在過濾其輸入的文件的名稱。請注意,除非 jq 在 UTF-8 語言環境中運行,否則這將無法正常工作。

input_line_number

返回當前被過濾的輸入的行號。

流式操作

使用--stream選項 jq 可以以流方式解析輸入文本,允許 jq 程序立即開始處理大型 JSON 文本,而不是在解析完成後。如果您有一個大小爲 1GB 的 JSON 文本,流式傳輸將使您能夠更快地處理它。

然而,流處理並不容易,因爲 jq 程序將[<path>, <leaf-value>](和一些其他形式)作爲輸入。

提供了幾個內置函數以使處理流更容易。

下面的示例使用 的流式形式[0,[1]],即 [[0],0],[[1,0],1],[[1,0]],[[1]].

流形式包括[<path>, <leaf-value>](表示任何標量值、空數組或空對象)和[<path>](表示數組或對象的結尾)。未來版本的 jq 運行--stream-seq可能輸出其他形式,例如 ["error message"]當輸入文本無法解析時。

truncate_stream(stream_expression)

使用一個數字作爲輸入,並從給定流表達式的輸出左側截斷相應數量的路徑元素。

fromstream(stream_expression)

輸出與流表達式的輸出對應的值。

tostream

tostream內置輸出其輸入的流式形式。

任務

jq 中的賦值工作與大多數編程語言中的工作方式略有不同。jq 不區分對某事物的引用和副本——兩個對象或數組相等或不相等,沒有任何進一步的“相同對象”或“不同對象”的概念。

如果一個對象有兩個字段,它們是數組.foo.bar,並且你在 上附加了一些東西.foo,那麼.bar即使你之前設置了 ,也不會變大.bar = .foo。如果您習慣於使用 Python、Java、Ruby、Javascript 等語言進行編程,那麼您可以將其想象爲 jq 在執行分配之前對每個對象進行了完整的深度複製(出於性能考慮,它實際上並沒有這樣做,但這是一般的想法)。

這意味着不可能在 jq 中構建循環值(例如第一個元素是自身的數組)。這是非常有意的,並確保 jq 程序可以生成的任何內容都可以用 JSON 表示。

jq 中的所有賦值運算符在左側(LHS)都有路徑表達式。右側 (RHS) 提供設置爲由 LHS 路徑表達式命名的路徑的值。

jq 中的值始終是不可變的。在內部,賦值通過使用歸約來計算新的替換值,.所有期望的賦值都應用於.,然後輸出修改後的值。這個可以說明這一點:{a:{b:{c:1}}} | (.a.b|=3), .. 這將輸出 {"a":{"b":3}}{"a":{"b":{"c":1}}}因爲最後一個子表達式., 看到的是原始值,而不是修改後的值。

大多數用戶都希望使用修改賦值運算符,例如|=or +=,而不是=

請注意,賦值運算符的 LHS 是指 .. 因此$var.foo = 1不會按預期工作($var.foo在 中不是有效或有用的路徑表達式.);改爲使用$var | .foo = 1

還要注意,.a,.b=0不設置.aand .b,而是 (.a,.b)=0設置兩者。

更新分配:|=

這是“更新”運算符'|='。它在右側採用一個過濾器,並.通過該表達式運行舊值來計算分配給的屬性的新值。例如, (.foo, .bar) |= .+1 將構建一個對象,其中“foo”字段設置爲輸入的“foo”加 1,“bar”字段設置爲輸入的“bar”加 1 .

左側可以是任何通用路徑表達式;見path()

請注意,'|=' 的左側指的是.. 因此$var.foo |= . + 1不會按預期工作($var.foo在 中不是有效或有用的路徑表達式.);改爲使用$var | .foo |= . + 1

如果右側不輸出任何值(即empty),則左側路徑將被刪除,與 一樣del(path)

如果右側輸出多個值,則僅使用第一個值(兼容性說明:在 jq 1.5 及更早版本中,過去是僅使用最後一個)。

算術更新賦值:+=-=*=/=%=,//=

jq 有幾個形式的運算符a op= b,它們都等價於a |= . op b. 因此,+= 1可用於增加值,與|= . + 1.

簡單的分配:=

這是普通的賦值運算符。與其他不同的是,右側 (RHS) 的輸入與左側 (LHS) 的輸入相同,而不是 LHS 路徑上的值,並且 RHS 輸出的所有值都將是使用(如下圖)。

如果 '=' 的 RHS 產生多個值,那麼對於每個這樣的值 jq 將左側的路徑設置爲該值,然後它將輸出修改後的.. 例如, (.a,.b)=range(2)輸出{"a":0,"b":0},然後 {"a":1,"b":1}。“更新”分配表格(見上文)不這樣做。

這個應該顯示 '=' 和 '|=' 之間的區別:

向程序提供輸入 '{"a": {"b": 10}, "b": 20}':

.a = .b

.a |= .b

前者將輸入的“a”字段設置爲輸入的“b”字段,併產生輸出{“a”:20,“b”:20}。後者會將輸入的“a”字段設置爲“a”字段的“b”字段,產生{“a”:10,“b”:20}。

'=' 和 '|=' 之間區別的另一個:

空|(.a,.b)=範圍(3)

輸出 '{"a":0,"b":0}'、'{"a":1,"b":1}' 和 '{"a":2,"b":2}',儘管

空|(.a,.b)|=範圍(3)

只輸出'{"a":0,"b":0}'。

複雜的任務

與大多數語言相比,jq 賦值左側允許的內容更多。我們已經在左側看到了簡單的字段訪問,數組訪問也同樣有效也就不足爲奇了:

.posts[0].title = "JQ Manual"

令人驚訝的是,左邊的表達式可能會產生多個結果,指的是輸入文檔中的不同點:

.posts[].comments |= . + ["this is great"]

該示例將字符串“this is great”附加到輸入中每個帖子的“comments”數組(其中輸入是具有字段“posts”的對象,該字段是帖子數組)。

當 jq 遇到像 'a = b' 這樣的賦值時,它會記錄在執行 a 時選擇輸入文檔的一部分所採用的“路徑”。然後,此路徑用於查找在執行分配時要更改輸入的哪一部分。任何過濾器都可以用在等號的左側——它從輸入中選擇的任何路徑都將是執行分配的地方。

這是一個非常強大的操作。假設我們想爲博客文章添加評論,使用上面相同的“博客”輸入。這一次,我們只想評論“stedolan”寫的帖子。我們可以使用前面描述的“選擇”功能找到這些帖子:

.posts[] | select(.author == "stedolan")

該操作提供的路徑指向“stedolan”寫的每一個帖子,我們可以像之前一樣對每一個帖子進行評論:

(.posts[] | select(.author == "stedolan") | .comments) |=
    . + ["terrible."]

模塊

jq 有一個庫/模塊系統。模塊是名稱以 . 結尾的文件.jq

程序導入的模塊在默認搜索路徑中搜索(見下文)。和指令允許導入importinclude更改此路徑。

搜索路徑中的路徑會受到各種替換。

對於以“~/”開頭的路徑,用戶的主目錄將替換爲“~”。

對於以“$ORIGIN/”開頭的路徑,jq 可執行文件的路徑將替換爲“$ORIGIN”。

對於以“./”開頭的路徑或以“.”開頭的路徑,包含文件的路徑將替換爲“.”。對於命令行上給出的頂級程序,使用當前目錄。

導入指令可以選擇指定附加默認值的搜索路徑。

默認搜索路徑是賦予-L 命令行選項 else的搜索路徑["~/.jq", "$ORIGIN/../lib/jq", "$ORIGIN/../lib"]

Null 和空字符串路徑元素終止搜索路徑處理。

將在給定搜索路徑的“foo/bar.jq”和“foo/bar/bar.jq”中搜索具有相對路徑“foo/bar”的依賴項。這旨在允許將模塊與例如版本控制文件、自述文件等一起放置在目錄中,但也允許單文件模塊。

不允許具有相同名稱的連續組件以避免歧義(例如,“foo/foo”)。

例如,可以在 和中找到-L$HOME/.jq一個模塊。foo$HOME/.jq/foo.jq$HOME/.jq/foo/foo.jq

如果“$HOME/.jq”是一個文件,它會被引入主程序。

import RelativePathString as NAME [<metadata>];

導入在相對於搜索路徑中的目錄的給定路徑中找到的模塊。“.jq”後綴將添加到相對路徑字符串中。模塊的符號以“NAME::”爲前綴。

可選元數據必須是常量 jq 表達式。它應該是一個帶有“主頁”等鍵的對象。此時 jq 只使用元數據的“搜索”鍵/值。元數據也通過 modulemeta內置提供給用戶。

元數據中的“搜索”鍵(如果存在)應具有字符串或數組值(字符串數組);這是作爲頂級搜索路徑前綴的搜索路徑。

include RelativePathString [<metadata>];

導入在給定路徑中找到的模塊,該模塊相對於搜索路徑中的目錄,就好像它被包含在適當位置一樣。“.jq”後綴將添加到相對路徑字符串中。模塊的符號被導入調用者的命名空間,就好像模塊的內容被直接包含在內一樣。

可選元數據必須是常量 jq 表達式。它應該是一個帶有“主頁”等鍵的對象。此時 jq 只使用元數據的“搜索”鍵/值。元數據也通過 modulemeta內置提供給用戶。

import RelativePathString as $NAME [<metadata>];

導入在相對於搜索路徑中的目錄的給定路徑中找到的 JSON 文件。“.json”後綴將添加到相對路徑字符串中。該文件的數據將以$NAME::NAME.

可選元數據必須是常量 jq 表達式。它應該是一個帶有“主頁”等鍵的對象。此時 jq 只使用元數據的“搜索”鍵/值。元數據也通過 modulemeta內置提供給用戶。

元數據中的“搜索”鍵(如果存在)應具有字符串或數組值(字符串數組);這是作爲頂級搜索路徑前綴的搜索路徑。

module <metadata>;

該指令完全是可選的。它不是正確操作所必需的。它僅用於提供可以使用modulemeta內置函數讀取的元數據。

元數據必須是常量 jq 表達式。它應該是一個帶有“主頁”之類的鍵的對象。此時 jq 不使用此元數據,但它通過 modulemeta內置提供給用戶。

modulemeta

將模塊名稱作爲輸入並將模塊的元數據作爲對象輸出,模塊的導入(包括元數據)作爲“deps”鍵的數組值。

程序可以使用它來查詢模塊的元數據,然後他們可以使用它來搜索、下載和安裝缺少的依賴項。

顏色

要配置替代顏色,只需將JQ_COLORS 環境變量設置爲以冒號分隔的部分終端轉義序列列表,如"1;31",按以下順序:

  • 顏色爲null
  • 顏色爲false
  • 顏色爲true
  • 數字的顏色
  • 字符串的顏色
  • 數組的顏色
  • 物體的顏色

默認配色方案與設置相同 "JQ_COLORS=1;30:0;37:0;37:0;37:0;32:1;37:1;37"

這不是 VT100/ANSI 轉義的手冊。但是,這些顏色規範中的每一個都應包含兩個用分號分隔的數字,其中第一個數字是以下數字之一:

  • 1(亮)
  • 2(暗淡)
  • 4(下劃線)
  • 5(閃爍)
  • 7(反向)
  • 8(隱藏)

第二個是其中之一:

  • 30(黑色)
  • 31(紅色)
  • 32(綠色)
  • 33(黃色)
  • 34(藍色)
  • 35(洋紅色)
  • 36(青色)
  • 37(白色)

 

高級用法示例

打印json中around屬性中的OtherCars屬性中的數組中第12個元素大於0的數組,其中點號表示當前節點即around.OtherCars[]:

 

彙總:

  jq可以將JSON來切片、過濾、映射和轉換結構化數據,就像 ,sedawkgrep 讓您玩文本一樣容易。

  jq很靈活,再搭配着其他bash命令那就不要太強大啦~

 

參考:

https://github.com/stedolan/jq

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章