问题描述
我有一个相当简单的bash脚本,我想根据环境变量的值启用或禁用jq过滤器。
这是脚本的简化版本:
i lat lon name country continent elevation type value Rep.$ Rep.D Rep.G Rep.H Rep.P Rep.S Rep.T Rep.V Rep.W Rep.Dp Rep.Pt
0 3002 60.749 -0.854 BALTASOUND SCOTLAND EUROPE 15.0 Day 2019-12-31Z 1380 SW 34 79.5 1019 25 7.9 13000 8 4.6 F
1 3002 60.749 -0.854 BALTASOUND SCOTLAND EUROPE 15.0 Day 2020-01-01Z 0 SW 32 84.0 1018 21 7.5 13000 8 5.0 F
2 3002 60.749 -0.854 BALTASOUND SCOTLAND EUROPE 15.0 Day 2020-01-01Z 60 SW 34 81.7 1018 22 7.5 12000 8 4.6 F
3 3002 60.749 -0.854 BALTASOUND SCOTLAND EUROPE 15.0 Day 2020-01-01Z 120 SW 36 79.9 1017 24 7.9 11000 8 4.7 F
4 3002 60.749 -0.854 BALTASOUND SCOTLAND EUROPE 15.0 Day 2020-01-01Z 180 SW 40 82.3 1016 23 7.5 13000 8 4.7 F
5 3002 60.749 -0.854 BALTASOUND SCOTLAND EUROPE 15.0 Day 2020-01-01Z 240 SW 33 84.6 1015 18 8.0 12000 8 5.6 F
6 3002 60.749 -0.854 BALTASOUND SCOTLAND EUROPE 15.0 Day 2020-01-01Z 300 SW 33 85.3 1015 24 8.3 11000 8 6.0 F
7 3002 60.749 -0.854 BALTASOUND SCOTLAND EUROPE 15.0 Day 2020-01-01Z 360 WSW 41 89.0 1014 30 8.5 8000 8 6.8 F
8 3002 60.749 -0.854 BALTASOUND SCOTLAND EUROPE 15.0 Day 2020-01-01Z 420 SW 43 89.6 1013 28 8.7 7000 7 7.1 F
9 3002 60.749 -0.854 BALTASOUND SCOTLAND EUROPE 15.0 Day 2020-01-01Z 480 SW 39 88.4 1013 23 8.7 15000 7 6.9 F
10 3002 60.749 -0.854 BALTASOUND SCOTLAND EUROPE 15.0 Day 2020-01-01Z 540 SW 40 84.3 1013 29 9.1 19000 8 6.6 F
11 3002 60.749 -0.854 BALTASOUND SCOTLAND EUROPE 15.0 Day 2020-01-01Z 600 SW 41 85.4 1012 24 8.9 12000 8 6.6 F
12 3002 60.749 -0.854 BALTASOUND SCOTLAND EUROPE 15.0 Day 2020-01-01Z 660 SW 38 84.2 1012 28 9.2 13000 8 6.7 F
13 3002 60.749 -0.854 BALTASOUND SCOTLAND EUROPE 15.0 Day 2020-01-01Z 720 SW 47 83.6 1011 32 9.4 12000 8 6.8 F
14 3002 60.749 -0.854 BALTASOUND SCOTLAND EUROPE 15.0 Day 2020-01-01Z 780 WSW 45 84.8 1011 30 9.4 11000 8 7.0 F
15 3002 60.749 -0.854 BALTASOUND SCOTLAND EUROPE 15.0 Day 2020-01-01Z 840 SW 43 86.0 1010 28 9.4 11000 7 7.2 F
16 3002 60.749 -0.854 BALTASOUND SCOTLAND EUROPE 15.0 Day 2020-01-01Z 900 WSW 40 85.4 1009 29 9.4 12000 8 7.1 F
17 3002 60.749 -0.854 BALTASOUND SCOTLAND EUROPE 15.0 Day 2020-01-01Z 960 SW 39 86.0 1009 25 9.2 11000 8 7.0 F
18 3002 60.749 -0.854 BALTASOUND SCOTLAND EUROPE 15.0 Day 2020-01-01Z 1020 SW 33 87.8 1009 23 8.9 11000 8 7.0 F
19 3002 60.749 -0.854 BALTASOUND SCOTLAND EUROPE 15.0 Day 2020-01-01Z 1080 SW 36 85.5 1008 23 8.9 11000 8 6.6 F
20 3002 60.749 -0.854 BALTASOUND SCOTLAND EUROPE 15.0 Day 2020-01-01Z 1140 SW 40 86.6 1007 28 8.8 14000 8 6.7 F
21 3002 60.749 -0.854 BALTASOUND SCOTLAND EUROPE 15.0 Day 2020-01-01Z 1200 SSW 39 84.8 1006 28 8.8 13000 8 6.4 F
22 3002 60.749 -0.854 BALTASOUND SCOTLAND EUROPE 15.0 Day 2020-01-01Z 1260 SSW 37 87.7 1005 26 8.0 15000 8 6.1 F
23 3002 60.749 -0.854 BALTASOUND SCOTLAND EUROPE 15.0 Day 2020-01-01Z 1320 S 37 88.4 1003 24 8.0 13000 8 6.2 F
24 3002 60.749 -0.854 BALTASOUND SCOTLAND EUROPE 15.0 Day 2020-01-01Z 1380 S 38 89.6 1002 29 7.6 11000 8 6.0 F
25 3005 60.139 -1.183 LERWICK (S. SCREEN) SCOTLAND EUROPE 82.0 Day 2019-12-31Z 1380 W 41 89.5 1020 28 7.2 15000 8 5.6 F
当我使用JSON='{ "key1": { "name":"foo" },"key2": { "name":"bar" } }'
OPTIONAL_FILTER=""
if [[ "$FLAG" == "value" ]]; then
OPTIONAL_FILTER='| select(.key == "key2")'
fi
jq 'to_entries[] '${OPTIONAL_FILTER}' | .value.name' <<< $JSON
运行脚本时,一切都会按预期进行,并得到输出:
FLAG=""
但是,如果我设置"foo"
"bar"
,则会出现以下错误:
FLAG="value"
当我在zsh中运行相同的命令时,我没有得到此错误,而得到的只是jq: error: syntax error,unexpected $end (Unix shell quoting issues?) at <top-level>,line 1:
to_entries[] |
jq: 1 compile error
的预期输出
我对shell脚本的经验不是很丰富。我猜想有一个空字符或其他输入终止符,例如被插入到我的字符串中,但是我无法确认这一点或找到一个好的替代方法。这特别令人讨厌,因为它似乎是特定于shell的。我在大多数测试中都使用的zsh可以很好地处理代码。我只有在尝试运行看到错误的"foo"
脚本时才会收到该错误。
最终目的是使可选过滤器正常工作。如果我错过了某个特定于jq的选项,我可以选择其他方式。我尝试使用.sh
,但得到了jq 'to_entries[] $ENV.OPTIONAL_FILTER | .value.name' <<< $JSON
jq: error: syntax error,unexpected '$',expecting $end
解决方法
如果可能的话,几乎总是最好避免通过字符串插值来操纵程序文本。幸运的是,据我所知,使用jq不仅可能,而且非常简单。
在当前情况下,您可以使用--arg命令行选项,例如:
jq --arg flag "$FLAG" '
to_entries[]
| if $flag == "value" then select(.key == "key2")
else . end
| .value.name' <<< $JSON
,
您插入${OPTIONAL_FILTER}
的方式将其拆分为多个单词,这意味着jq
收到的参数超出了预期。 Bash将命令解释为如同您编写的一样:
jq 'to_entries[] |' 'select(.key' '==' '"key2")' '| .value.name' <<< $JSON
您可以引用它以确保它是一个单词:
jq 'to_entries[] '"${OPTIONAL_FILTER}"' | .value.name' <<< $JSON
或者在整个文本中使用双引号,这样您就不必跳入或跳出单引号:
jq "to_entries[] ${OPTIONAL_FILTER} | .value.name" <<< $JSON
有关更多信息,请参见: