學習軌道
/
jq
jq
/
練習
/
千層麵
千層麵

千層麵

學習練習

簡介

變數

回想一下,jq程式是一條_運算式管線_。 變數賦值遵循這條規則:_變數賦值_是一種看起來像這樣的運算式:

... | expr as $varname | ...

篩選器的輸出就是它的輸入

跟_恆等運算式_.一樣,_變數賦值_的輸出和它的輸入相同。 設定變數的值是一種副作用。

範例:可以看到賦值之後的.和最初的輸入相同:

$ jq -c -n '42 | (. * 2) as $double | [., $double]'
[42,84]

變數的作用域

變數的作用域是「詞法」的,也就是說,變數在管線剩下的部分都會在作用域內。 在函式內定義的變數(我們之後會談到函式)是函式的「區域」變數。

變數名稱

變數必須以$開頭。 變數名稱剩下的部分是識別字:以字母或底線開頭,後面接著字母、數字或底線。

解構賦值

手冊上寫道:

只要提供一個_符合輸入結構_的模式,就能用單一的as運算式宣告多個變數(這稱為「解構」)。

範例:

[1, 2, 3] as [$a, $b, $c]
| [$a, $b, $c]     # => [1, 2, 3]
{"foo": "bar", "len": [10, 20]} as {foo: $f, len: [$h, $w]}
| [$f, $h, $w]     # => ["bar", 10, 20]

把變數名稱對應到_物件鍵_是一種簡寫:

{"x": 4, "y": 7} as {$x, $y}
| [$x, $y]         # => [4, 7]
{"foo": "bar", "len": [10, 20]} as {$foo, $len}
| [$foo, $len]     # => ["bar", [10, 20]]
Note

同樣的簡寫反過來也適用於_物件建構_

4 as $x | 7 as $y | {$x, $y}    # => {"x":4, "y": 7}

常數

如上面的範例所示,變數很方便用來儲存常數。 比起讓「魔術數字」出現在程式碼裡,更好的做法是給常數取個名字。

很多時候不需要變數

省略變數通常更好讀。

想想看計算某個數字陣列平均值的情況

[2, 4, 8, 7]
| add as $sum
| length as $len
| $sum / $len

和下面這種寫法相比:

[2, 4, 8, 7] | add / length

這凸顯了jq最強大的特點之一:篩選器的輸入會提供給_每一個_子運算式:

  • 輸入陣列[2,4,8,7]會傳給add(它對所有元素套用+運算子來加總這些數字)
  • 同時,[2,4,8,7]也會傳給length
  • 等這些子運算式都完成後,再把它們的結果相除,回傳輸入陣列中這些數字的平均值。

學習練習會用到的jq運算子

替代運算子://

運算式a // b在a是 false 或 null 時輸出b,否則輸出a。 在設定變數的情境下,這對於提供預設值非常方便:

(.input.theAnswer // 42) as $answer | ...
算術運算子
  • +、-、*就是一般數字用的加法、減法和乘法運算子。

說明

在這個練習中,你將寫一些程式碼,幫助你依照最愛的食譜做出美味的千層麵。

你有四項任務,全都和烹調千層麵所花費的時間有關。

1. 定義預計的烤箱時間(以分鐘為單位)

定義一個名為$expected_minutes_in_oven的常數。 根據食譜,烤箱的預計時間是 40 分鐘:

$ jq -n -f lasagna.jq
{
  "expected_minutes_in_oven": 40,
  ...

2. 計算剩餘的烤箱時間(以分鐘為單位)

這個值會以千層麵實際已經待在烤箱裡的分鐘數作為輸入,並根據上一項任務得到的烤箱預計時間,回傳千層麵還需要留在烤箱裡幾分鐘。

$ echo '{"actual_minutes_in_oven": 18}' | jq -f lasagna.jq
{
  "expected_minutes_in_oven": 40,
  "remaining_minutes_in_oven": 22,
  ...

3. 計算準備時間(以分鐘為單位)

準備時間是指千層麵放進烤箱之前,需要花多少時間準備好。 每一層需要花 2 分鐘準備。

$ echo '{"number_of_layers": 3}' | jq -f lasagna.jq
{
  ...
  "preparation_time": 6,
  ...

4. 計算總工作時間(以分鐘為單位)

計算你烹調千層麵總共花了幾分鐘。 這是準備時間的分鐘數,加上千層麵目前已經待在烤箱裡的分鐘數。

$ echo '{"actual_minutes_in_oven": 10, "number_of_layers": 2}' | jq -f lasagna.jq
{
  ...
  "total_time": 14,
  ...
透過 GitHub 編輯 連結會在新視窗或分頁中開啟
jq Exercism

準備好開始 千層麵 了嗎?

註冊 Exercism,透過 12 個概念75 個練習 和真人引導來學習並精通 jq,全部免費。