json1-4 Exercise 2: Ten Questions, Ten Filters, Checked ======================================================= Run in Git Bash with jq 1.8.2 on PATH: bash ex2.sh (uses the shop.json from exercise 1) --- ex2.sh --- # Exercise 2: ten questions about shop.json, each answered with one jq filter and checked against a value worked out by hand export PATH="/c/lwdj/json/c4/bin:$PATH" pass=0; fail=0 check() { # label, expected, filter, [jq options] local label=$1 expected=$2 filter=$3; shift 3 local got; got=$(jq "$@" "$filter" shop.json 2>&1 | tr -d '\r') if [ "$got" = "$expected" ]; then pass=$((pass+1)); printf 'PASS %-32s %s\n' "$label" "$got" else fail=$((fail+1)); printf 'FAIL %-32s expected %s | got %s\n' "$label" "$expected" "$got"; fi } check "names of products in stock" '["Tea","Biscuits","Milk"]' '[.products[] | select(.stock > 0) | .name]' -c check "how many are out of stock" '1' '[.products[] | select(.stock == 0)] | length' check "total stock" '175' '[.products[].stock] | add' check "average price" '2.6575' '[.products[].price] | add / length' check "cheapest product name" 'Milk' '.products | min_by(.price) | .name' -r check "owner full name" 'Ada Lovelace' '.owner.first + " " + .owner.last' -r check "names joined with commas" 'Tea, Coffee, Biscuits, Milk' '[.products[].name] | join(", ")' -r check "hot drinks" '["Tea","Coffee"]' '[.products[] | select(.tags != null and (.tags | index("hot"))) | .name]' -c check "sku,stock lines as CSV" '"A1",40 "B2",0 "C3",120 "D4",15' '.products[] | [.sku, .stock] | @csv' -r check "products with no tags field" '["D4"]' '[.products[] | select(has("tags") | not) | .sku]' -c echo "-- control: a wrong expectation on purpose" check "average price (wrong on purpose)" '3' '[.products[].price] | add / length' echo echo "passed: $pass failed: $fail (the one failure is the control)" echo echo "-- a filter that matches nothing, with and without -e" jq '.products[] | select(.price > 100)' shop.json; echo "exit without -e: $?" jq -e '.products[] | select(.price > 100)' shop.json; echo "exit with -e : $?" jq -e '.owner.phone' shop.json; echo "exit with -e on null: $?" Output: PASS names of products in stock ["Tea","Biscuits","Milk"] PASS how many are out of stock 1 PASS total stock 175 PASS average price 2.6575 PASS cheapest product name Milk PASS owner full name Ada Lovelace PASS names joined with commas Tea, Coffee, Biscuits, Milk PASS hot drinks ["Tea","Coffee"] PASS sku,stock lines as CSV "A1",40 "B2",0 "C3",120 "D4",15 PASS products with no tags field ["D4"] -- control: a wrong expectation on purpose FAIL average price (wrong on purpose) expected 3 | got 2.6575 passed: 10 failed: 1 (the one failure is the control) -- a filter that matches nothing, with and without -e exit without -e: 0 exit with -e : 4 null exit with -e on null: 1 WHY THIS WORKS AS AN ANSWER --------------------------- Each answer was worked out by hand before the run (for example 40 + 0 + 120 + 15 = 175 for the total stock, and 10.63 / 4 = 2.6575 for the average), so the PASS lines compare jq with an independent value and not with itself. The single FAIL is the control: I wrote a wrong expectation (3) for the average on purpose, and the checker reported it, so a PASS is meaningful. The last block shows the three exit statuses of -e: a filter that matches nothing exits 0 without -e, and 4 with -e; a null result exits 1 with -e. Note the cheap trap in the "no tags" question: select(.tags | not) would be wrong, because it also needs to treat a missing key and a null value the same, and has("tags") | not tests for the key itself.