Bash jq 查询的变量替换总是 returns null
Bash variable substitution for jq query always returns null
从公司系统导出的文件在我无法更改的结构中生成 json。在 bash (v5.0.2) 中基于变量搜索特定属性时,在使用任何替换元素时它总是 returns null。
如果我对要搜索的值进行硬编码,它就可以工作。
但是,需要能够使用变量来支持代码逻辑,而不必硬编码细节,尤其是要处理 1000 条记录。
使用下面 json 的示例摘录和下面的代码,这显示了我根据我从 jq 手册中可以理解的内容所做的尝试。
{
"status": true,
"payload": {
"customerData": {
"101": {
"title": "A Company",
"id": "101",
"storageGroups": "SHIPPING",
"priority": "4",
"originalname": "A Previous Company",
"allowShipping": true,
"parentCompany": "0",
"rating": 0,
"external": false,
"application": "primary",
"applicationName": "form27",
"live": true,
"logo": "http://url",
"beta": false,
"length": null,
"token": "QSBQcmV2aW91cyBDb21wYW55LzEwMQ==",
"active": "1"
}
}
}
}
简单的 bash 脚本来证明目前已测试的方法
#!/bin/bash
chkCustomer=101
chkFile="json-simple.txt"
if [[ ! -s "${chkFile}" ]] ; then exit 1 ; fi
tokenTry1=$(cat "${chkFile}" | jq -r '.payload.customerData."${chkCustomer}".token')
printf "%s\n" "Try 1 Returned ${tokenTry1}"
tokenTry2=$(cat "${chkFile}" | jq -r '.payload.customerData."$chkCustomer".token')
printf "%s\n" "Try 2 Returned ${tokenTry2}"
tokenTry3=$(cat "${chkFile}" | jq -r --arg CHK ${chkCustomer} '.payload.customerData."$CHK".token')
printf "%s\n" "Try 3 Returned ${tokenTry3}"
tokenTry4=$(cat "${chkFile}" | jq -r --arg CHK ${chkCustomer} '.payload.customerData."env.$CHK".token')
printf "%s\n" "Try 4 Returned ${tokenTry4}"
tokenTry5=$(cat "${chkFile}" | jq -r --arg CHK 101 '.payload.customerData."$CHK".token')
printf "%s\n" "Try 5 Returned ${tokenTry5}"
tokenTry6=$(cat "${chkFile}" | jq -r '.payload.customerData.101.token')
printf "%s\n" "Try 6 Returned ${tokenTry6}"
tokenWorks=$(cat "${chkFile}" | jq -r '.payload.customerData."101".token')
printf "%s\n" "Try 7 (works) Returned ${tokenWorks}"
仅尝试 7 次即可获得有效响应。所有其余的都是 null
或失败。
针对 json 的脚本输出是
Try 1 Returned null
Try 2 Returned null
Try 3 Returned null
Try 4 Returned null
Try 5 Returned null
jq: error: Invalid numeric literal at EOF at line 1, column 5 (while parsing '.101.') at <top-level>, line 1:
.payload.customerData.101.token
jq: error: syntax error, unexpected LITERAL, expecting $end (Unix shell quoting issues?) at <top-level>, line 1:
.payload.customerData.101.token
jq: 2 compile errors
Try 6 Returned
Try 7 (works) Returned QSBQcmV2aW91cyBDb21wYW55LzEwMQ==
我需要(或期望)的是我可以使用变量并执行 jq 查询来获得结果。
我确定我遗漏了一些非常明显的东西,但我无法理解这一点。查看我在 SO 上发现的其他问题,none 已经有所帮助。
在额外的单引号内使用 bash 变量来拆分命令,然后转义双引号以进行实际变量替换,解决了这个问题。
工作代码示例,使用与原始问题相同的json。
#!/bin/bash
chkCustomer=101
chkFile="json-simple.txt"
companyToken=$(jq -r '.payload.customerData.'\"${chkCustomer}\"'.token' "${chkFile}")
printf "%s\n" "Company token for ${chkCustomer} is ${companyToken}."
无论 bash 变量本身是否被引用,此方法都有效。如果没有双引号转义,它会失败。
执行此操作的安全方法是从代码中带外传递变量。即:
#!/bin/bash
chkCustomer=101
chkFile="json-simple.txt"
companyToken=$(jq -r --arg chkCustomer "$chkCustomer" \
'.payload.customerData[$chkCustomer].token' "$chkFile")
printf "%s\n" "Company token for ${chkCustomer} is ${companyToken}."
单引号字符串中的 $chkCustomer
由 shell 单独保留,而由 jq
本身解释为引用通过 [=13 传入的字符串值=].
这可以防止包含 jq
代码的 chkCustomer
值生成实际上不符合输入文件内容的输出,或者 -- 将来,当 jq添加 I/O 原语 -- 执行文件 I/O 并更改磁盘内容的原语。
从公司系统导出的文件在我无法更改的结构中生成 json。在 bash (v5.0.2) 中基于变量搜索特定属性时,在使用任何替换元素时它总是 returns null。 如果我对要搜索的值进行硬编码,它就可以工作。 但是,需要能够使用变量来支持代码逻辑,而不必硬编码细节,尤其是要处理 1000 条记录。
使用下面 json 的示例摘录和下面的代码,这显示了我根据我从 jq 手册中可以理解的内容所做的尝试。
{
"status": true,
"payload": {
"customerData": {
"101": {
"title": "A Company",
"id": "101",
"storageGroups": "SHIPPING",
"priority": "4",
"originalname": "A Previous Company",
"allowShipping": true,
"parentCompany": "0",
"rating": 0,
"external": false,
"application": "primary",
"applicationName": "form27",
"live": true,
"logo": "http://url",
"beta": false,
"length": null,
"token": "QSBQcmV2aW91cyBDb21wYW55LzEwMQ==",
"active": "1"
}
}
}
}
简单的 bash 脚本来证明目前已测试的方法
#!/bin/bash
chkCustomer=101
chkFile="json-simple.txt"
if [[ ! -s "${chkFile}" ]] ; then exit 1 ; fi
tokenTry1=$(cat "${chkFile}" | jq -r '.payload.customerData."${chkCustomer}".token')
printf "%s\n" "Try 1 Returned ${tokenTry1}"
tokenTry2=$(cat "${chkFile}" | jq -r '.payload.customerData."$chkCustomer".token')
printf "%s\n" "Try 2 Returned ${tokenTry2}"
tokenTry3=$(cat "${chkFile}" | jq -r --arg CHK ${chkCustomer} '.payload.customerData."$CHK".token')
printf "%s\n" "Try 3 Returned ${tokenTry3}"
tokenTry4=$(cat "${chkFile}" | jq -r --arg CHK ${chkCustomer} '.payload.customerData."env.$CHK".token')
printf "%s\n" "Try 4 Returned ${tokenTry4}"
tokenTry5=$(cat "${chkFile}" | jq -r --arg CHK 101 '.payload.customerData."$CHK".token')
printf "%s\n" "Try 5 Returned ${tokenTry5}"
tokenTry6=$(cat "${chkFile}" | jq -r '.payload.customerData.101.token')
printf "%s\n" "Try 6 Returned ${tokenTry6}"
tokenWorks=$(cat "${chkFile}" | jq -r '.payload.customerData."101".token')
printf "%s\n" "Try 7 (works) Returned ${tokenWorks}"
仅尝试 7 次即可获得有效响应。所有其余的都是 null
或失败。
针对 json 的脚本输出是
Try 1 Returned null
Try 2 Returned null
Try 3 Returned null
Try 4 Returned null
Try 5 Returned null
jq: error: Invalid numeric literal at EOF at line 1, column 5 (while parsing '.101.') at <top-level>, line 1:
.payload.customerData.101.token
jq: error: syntax error, unexpected LITERAL, expecting $end (Unix shell quoting issues?) at <top-level>, line 1:
.payload.customerData.101.token
jq: 2 compile errors
Try 6 Returned
Try 7 (works) Returned QSBQcmV2aW91cyBDb21wYW55LzEwMQ==
我需要(或期望)的是我可以使用变量并执行 jq 查询来获得结果。
我确定我遗漏了一些非常明显的东西,但我无法理解这一点。查看我在 SO 上发现的其他问题,none 已经有所帮助。
在额外的单引号内使用 bash 变量来拆分命令,然后转义双引号以进行实际变量替换,解决了这个问题。
工作代码示例,使用与原始问题相同的json。
#!/bin/bash
chkCustomer=101
chkFile="json-simple.txt"
companyToken=$(jq -r '.payload.customerData.'\"${chkCustomer}\"'.token' "${chkFile}")
printf "%s\n" "Company token for ${chkCustomer} is ${companyToken}."
无论 bash 变量本身是否被引用,此方法都有效。如果没有双引号转义,它会失败。
执行此操作的安全方法是从代码中带外传递变量。即:
#!/bin/bash
chkCustomer=101
chkFile="json-simple.txt"
companyToken=$(jq -r --arg chkCustomer "$chkCustomer" \
'.payload.customerData[$chkCustomer].token' "$chkFile")
printf "%s\n" "Company token for ${chkCustomer} is ${companyToken}."
单引号字符串中的 $chkCustomer
由 shell 单独保留,而由 jq
本身解释为引用通过 [=13 传入的字符串值=].
这可以防止包含 jq
代码的 chkCustomer
值生成实际上不符合输入文件内容的输出,或者 -- 将来,当 jq添加 I/O 原语 -- 执行文件 I/O 并更改磁盘内容的原语。