Подстановка переменной Bash для jq-запроса всегда возвращает ноль - PullRequest
0 голосов
/ 30 марта 2019

При экспорте файлов из системы компании создается структура json, которую я не могу изменить. При поиске определенных атрибутов, основанных на переменных в bash (v5.0.2), он всегда возвращает ноль при использовании любого элемента подстановки. Если я жестко закодирую значение для поиска, это работает. Однако необходимо иметь возможность использовать переменные для поддержки логики кода и не требовать жесткой специфики кода, особенно с учетом тысяч записей для обработки.

Используя пример извлечения 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, ни один еще не помог.

Ответы [ 2 ]

3 голосов
/ 30 марта 2019

безопасный способ сделать это состоит в том, чтобы передать ваши переменные вне вашего кода. То есть:

#!/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 в строке в одинарных кавычках оставляется оболочкой в ​​одиночку и вместо этого интерпретируется самой jq как ссылка на строковое значение, переданное через --arg.

Это препятствует тому, чтобы значение chkCustomer, содержащее код jq, могло генерировать вывод, который фактически не соответствует содержимому входного файла, или - в будущем, когда jq добавит примитивы ввода / вывода - - тот, который выполняет файловый ввод-вывод и изменяет содержимое вашего диска.

1 голос
/ 30 марта 2019

Использование переменной 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 в кавычках или нет. Без двойных кавычек ничего не получается.

...