Как использовать jq для форматирования JSON со встроенным, экранированным / строковым JSON (для любых / всех структур)?

1

Есть много вопросов, которые говорят: "У меня есть такая точная структура JSON, пожалуйста, сделайте мою домашнюю работу для меня и сделайте так, чтобы она имела эту другую точную структуру". Это НЕ один из тех вопросов.

Я хочу видеть jq скрипты для очистки общих данных. Ниже я опубликую ответ, который работает довольно хорошо для большинства данных, которые я получаю из своих журналов. Но, учитывая, что здесь много умных людей, я хочу посмотреть, что придут другие.

Примечание: это не дубликат других вопросов, потому что природа каждого вопроса, который я видел на SO, приводит к ответам, которые в значительной степени полезны только для OP. Ответы на этот вопрос должны быть полезны всем, прибегая к помощи чего-то подобного. Какой-нибудь удачливый ответчик получит репутационную бомбу, как я сделал с моим ответом здесь.

  • 0
    «Очистка общих данных» довольно широка, по крайней мере, для тех, кто не знаком с вашими журналами. Даже при том, что у вас есть общий вопрос, следование минимальным воспроизводимым примерам примеров будет хорошей идеей.
  • 0
    Если бы мое единственное направление было «очистить общие данные», это было бы слишком широко. Но я назвал вопрос JSON в JSON и привел пример. Часть, которую я хочу назвать общей, - это структура источника, а не проблема, которую нужно исправить.
Показать ещё 2 комментария
Теги:
jq

2 ответа

1

Выполнение fromjson для всех строк может быть выполнено, например, с помощью walk и ? :

walk(if type == "string" then fromjson? // . else . end)

Оставляя только числовые строки

walk(if type == "string"
     then if tonumber? // false then . 
          else fromjson? // . end
     else . end)
  • 0
    Это довольно эффективно. У него, к сожалению, есть побочный эффект преобразования "EventVersion": "1.0" в "EventVersion": 1.0 из моего образца JSON, но мне это очень нравится для инструмента «Мне нужно прочитать этот минимизированный беспорядок». Спасибо за вклад.
  • 0
    Если вы не хотите, чтобы числовые строки были преобразованы в числа, то вы можете легко избежать этого, используя tonumber? или test с подходящим регулярным выражением.
Показать ещё 1 комментарий
0

Предполагая, что весь встроенный JSON является минимизированным словарем (как в случае с моим выводом Terraform, выводом AWS cli и журналами AWS), этот один jq скрипт творит чудеса.

jq 'walk(if type == "string" and .[0:2] == "{\"" then .=(.|fromjson) else . end)'

Он работает, обходя объект json в поисках строк, начинающихся с {" и использует подпроцесс для fromjson их через fromjson (никогда не покидая jq).

Я поместил его в функцию bash (jqp), потому что это проще, чем экранировать кавычки для псевдонима и НАМНОГО более гибко. Затем я могу использовать его для обработки содержимого файла или буфера обмена.

# This is in my .bash_profile
jqp(){
  jq 'walk(if type == "string" and .[0:2] == "{\"" then .=(.|fromjson) else . end)' "$@"
}
# Here is an event trigger from SNS to Lambda
$ cat event.json
{
    "Records": [
        {
            "EventVersion": "1.0",
            "EventSubscriptionArn": "arn:aws:sns:us-east-1:123456789012:sns-to-slack-shared-services:a70df027-2c7f-492a-840a-633d44fd71a6",
            "EventSource": "aws:sns",
            "Sns": {
                "SignatureVersion": "1",
                "Timestamp": "2019-02-06T15:50:30.028Z",
                "Signature": "GN3712/aWjVLftSzdOcW5Zm32/uvfZKrCcvTmz6Obv/AXbz1xc22sTMYt2vFja7coHGhhO5bG6dz/IbJSx/Zm0U/dVVefWKukFl1umP3av+1JoUbbi+4uHai3k3AwQa3wR4HWjrKKmMt+Tkt/gm7jvhcuojtx+n5oc4S6bMsVq5OmSfAWd2Xd1urTm2zeGCL59nbfhZv+xB4db3dk62FtxVKtFXtvO2pH27+E3vXUvgu2k1c2Kd/Vt/vbYCAA==",
                "SigningCertUrl": "https://sns.us-east-1.amazonaws.com/SimpleNotificationService-a70df027-2c7f-492a-840a-633d44fd71a6.pem",
                "MessageId": "a8df3067-c347-55ce-b869-64b2c7c1d0a3",
                "Message": "{\"AlarmName\":\"unauthorized_api_calls_Count-alarm\",\"AlarmDescription\":\"This metric monitors unauthorized API calls\",\"AWSAccountId\":\"123456789012\",\"NewStateValue\":\"ALARM\",\"NewStateReason\":\"Threshold Crossed: 1 datapoint [5.0 (06/02/19 15:45:00)] was greater than or equal to the threshold (1.0).\",\"StateChangeTime\":\"2019-02-06T15:50:30.023+0000\",\"Region\":\"US East (N. Virginia)\",\"OldStateValue\":\"INSUFFICIENT_DATA\",\"Trigger\":{\"MetricName\":\"unauthorized_api_calls\",\"Namespace\":\"security_rules\",\"StatisticType\":\"Statistic\",\"Statistic\":\"SUM\",\"Unit\":null,\"Dimensions\":[],\"Period\":300,\"EvaluationPeriods\":1,\"ComparisonOperator\":\"GreaterThanOrEqualToThreshold\",\"Threshold\":1.0,\"TreatMissingData\":\"\",\"EvaluateLowSampleCountPercentile\":\"\"}}",
                "MessageAttributes": {},
                "Type": "Notification",
                "UnsubscribeUrl": "https://sns.us-east-1.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:us-east-1:123456789012:sns-to-slack-shared-services:a70df027-2c7f-492a-840a-633d44fd71a6",
                "TopicArn": "arn:aws:sns:us-east-1:123456789012:sns-to-slack-shared-services",
                "Subject": "ALARM: \"unauthorized_api_calls_Count-alarm\" in US East (N. Virginia)"
            }
        }
    ]
}

# Demonstrate that "$@" in the function allows the use of extra options
$ jqp --indent 4 event.json
{
    "Records": [
        {
            "EventVersion": "1.0",
            "EventSubscriptionArn": "arn:aws:sns:us-east-1:123456789012:sns-to-slack-shared-services:a70df027-2c7f-492a-840a-633d44fd71a6",
            "EventSource": "aws:sns",
            "Sns": {
                "SignatureVersion": "1",
                "Timestamp": "2019-02-06T15:50:30.028Z",
                "Signature": "GN3712/aWjVLftSzdOcW5Zm32/uvfZKrCcvTmz6Obv/AXbz1xc22sTMYt2vFja7coHGhhO5bG6dz/IbJSx/Zm0U/dVVefWKukFl1umP3av+1JoUbbi+4uHai3k3AwQa3wR4HWjrKKmMt+Tkt/gm7jvhcuojtx+n5oc4S6bMsVq5OmSfAWd2Xd1urTm2zeGCL59nbfhZv+xB4db3dk62FtxVKtFXtvO2pH27+E3vXUvgu2k1c2Kd/Vt/vbYCAA==",
                "SigningCertUrl": "https://sns.us-east-1.amazonaws.com/SimpleNotificationService-a70df027-2c7f-492a-840a-633d44fd71a6.pem",
                "MessageId": "a8df3067-c347-55ce-b869-64b2c7c1d0a3",
                "Message": {
                    "AlarmName": "unauthorized_api_calls_Count-alarm",
                    "AlarmDescription": "This metric monitors unauthorized API calls",
                    "AWSAccountId": "123456789012",
                    "NewStateValue": "ALARM",
                    "NewStateReason": "Threshold Crossed: 1 datapoint [5.0 (06/02/19 15:45:00)] was greater than or equal to the threshold (1.0).",
                    "StateChangeTime": "2019-02-06T15:50:30.023+0000",
                    "Region": "US East (N. Virginia)",
                    "OldStateValue": "INSUFFICIENT_DATA",
                    "Trigger": {
                        "MetricName": "unauthorized_api_calls",
                        "Namespace": "security_rules",
                        "StatisticType": "Statistic",
                        "Statistic": "SUM",
                        "Unit": null,
                        "Dimensions": [],
                        "Period": 300,
                        "EvaluationPeriods": 1,
                        "ComparisonOperator": "GreaterThanOrEqualToThreshold",
                        "Threshold": 1,
                        "TreatMissingData": "",
                        "EvaluateLowSampleCountPercentile": ""
                    }
                },
                "MessageAttributes": {},
                "Type": "Notification",
                "UnsubscribeUrl": "https://sns.us-east-1.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:us-east-1:123456789012:sns-to-slack-shared-services:a70df027-2c7f-492a-840a-633d44fd71a6",
                "TopicArn": "arn:aws:sns:us-east-1:123456789012:sns-to-slack-shared-services",
                "Subject": "ALARM: \"unauthorized_api_calls_Count-alarm\" in US East (N. Virginia)"
            }
        }
    ]
}
  • 0
    Обратите внимание, что .=(.|fromjson) можно упростить до fromjson : -!

Ещё вопросы

Сообщество Overcoder
Наверх
Меню