jq模板报错:<顶层>未定义,需更新samples列表变量值
解决jq模板变量未定义的报错问题
嘿,我帮你捋捋这个jq error: is not defined at <top-level>的问题——本质是你写的$uptime这类变量,jq压根没把它们当成你要填充的占位符,而是当成了它自己的内置变量,但这些变量你又没定义,所以就报错啦。下面给你几个实用的解决办法:
方法1:用命令行参数传递变量(最推荐)
如果你的变量是字符串或者数字这类简单类型,直接用jq的--arg(字符串)或--argjson(JSON类型,比如数字、布尔值)参数传值就好。
首先把你的模板文件(比如叫template.jq)保持原来的结构不变,变量还是用$xxx的形式:
{ "test": "abc", "p": "1", "v": "1.0.0", "samples": [ { "uptime": $uptime, "curr_connections": $curr_connections, "listen_disabled_num": $listen_disabled_num, "conn_yields": $conn_yields, "cmd_get": $cmd_get, "cmd_set": $cmd_set, "bytes_read": $bytes_read, "bytes_written": $bytes_written, "get_hits": $get_hits, "rejected_connections": $rejected_connections, "limit_maxbytes": $limit_maxbytes, "cmd_flush": $cmd_flush } ] }
然后执行命令的时候,把每个变量的值通过参数传进去:
jq --arg uptime "86400" \ --argjson curr_connections 150 \ --arg listen_disabled_num "0" \ --arg conn_yields "20" \ --arg cmd_get "1000" \ --arg cmd_set "300" \ --arg bytes_read "102400" \ --arg bytes_written "204800" \ --arg get_hits "900" \ --arg rejected_connections "0" \ --argjson limit_maxbytes 1073741824 \ --arg cmd_flush "1" \ -f template.jq /dev/null
这里加/dev/null是因为jq需要一个输入源,如果你没有其他JSON数据要处理,用空设备就行。
方法2:在jq脚本里提前定义变量
如果你不想每次都敲一堆命令行参数,可以把变量直接定义在jq脚本里,比如修改你的模板文件成这样:
# 先定义所有需要的变量 def uptime: "86400"; def curr_connections: 150; def listen_disabled_num: "0"; def conn_yields: "20"; def cmd_get: "1000"; def cmd_set: "300"; def bytes_read: "102400"; def bytes_written: "204800"; def get_hits: "900"; def rejected_connections: "0"; def limit_maxbytes: 1073741824; def cmd_flush: "1"; # 输出最终的JSON结构 { "test": "abc", "p": "1", "v": "1.0.0", "samples": [ { "uptime": uptime, "curr_connections": curr_connections, "listen_disabled_num": listen_disabled_num, "conn_yields": conn_yields, "cmd_get": cmd_get, "cmd_set": cmd_set, "bytes_read": bytes_read, "bytes_written": bytes_written, "get_hits": get_hits, "rejected_connections": rejected_connections, "limit_maxbytes": limit_maxbytes, "cmd_flush": cmd_flush } ] }
然后直接执行:
jq -f template.jq
这样jq就能识别你定义的变量,顺利生成JSON啦。
方法3:用占位符替换(适合非jq原生场景)
如果你只是把这个JSON当作文本模板,不想用jq的变量系统,可以把$uptime改成{{uptime}}这类占位符,然后用sed或者其他工具替换。比如模板文件template.json:
{ "test": "abc", "p": "1", "v": "1.0.0", "samples": [ { "uptime": "{{uptime}}", "curr_connections": "{{curr_connections}}", "listen_disabled_num": "{{listen_disabled_num}}", "conn_yields": "{{conn_yields}}", "cmd_get": "{{cmd_get}}", "cmd_set": "{{cmd_set}}", "bytes_read": "{{bytes_read}}", "bytes_written": "{{bytes_written}}", "get_hits": "{{get_hits}}", "rejected_connections": "{{rejected_connections}}", "limit_maxbytes": "{{limit_maxbytes}}", "cmd_flush": "{{cmd_flush}}" } ] }
然后用sed替换:
sed -e "s/{{uptime}}/86400/" \ -e "s/{{curr_connections}}/150/" \ -e "s/{{listen_disabled_num}}/0/" \ -e "s/{{conn_yields}}/20/" \ -e "s/{{cmd_get}}/1000/" \ -e "s/{{cmd_set}}/300/" \ -e "s/{{bytes_read}}/102400/" \ -e "s/{{bytes_written}}/204800/" \ -e "s/{{get_hits}}/900/" \ -e "s/{{rejected_connections}}/0/" \ -e "s/{{limit_maxbytes}}/1073741824/" \ -e "s/{{cmd_flush}}/1/" \ template.json
这种方式不需要依赖jq的语法,适合简单的批量替换场景。
最后提醒下:如果你的变量名和jq的内置函数重名,保险起见可以给变量加个前缀,比如$my_uptime,避免冲突哦。
内容的提问来源于stack exchange,提问作者nobrac




