Почему egrep
не дает мне все подходящие записи?
Это мой простой JSON-объект:
[nukaNUKA@dev-machine csv]$ cat jsonfile.json
{"number": 303,"projectName": "giga","queueId":8881,"result":"SUCCESS"}
Это мой файл с выкройками (чтобы я не пугал редактор):
[nukaNUKA@dev-machine csv]$ cat egrep-pattern.txt
\"number\":.*\"projectName
\"projectName\":.*,\"queueId
\"queueId\":.*,\"result
\"result\":\".*$
Это команда egrep / grep для индивидуального поиска, которая работает !:
[nukaNUKA@dev-machine csv]$ egrep -o "\"number\":.*\"projectName" jsonfile.json
"number": 303,"projectName
[nukaNUKA@dev-machine csv]$ egrep -o "\"projectName\":.*,\"queueId" jsonfile.json
"projectName": "giga","queueId
[nukaNUKA@dev-machine csv]$ egrep -o "\"queueId\":.*,\"result" jsonfile.json
"queueId":8881,"result
[nukaNUKA@dev-machine csv]$ egrep -o "\"result\":\".*$" jsonfile.json
"result":"SUCCESS"}
Итак, с этим не сработало ? Я не ношу очков, да.
[nukaNUKA@dev-machine csv]$ egrep -o "\"number\":.*\"projectName|\"projectName\":.*,\"queueId|\"queueId\":.*,\"result|\"result\":\".*$" jsonfile.json
"number": 303,"projectName
"queueId":8881,"result
[nukaNUKA@dev-machine csv]$ egrep -o -f egrep-pattern.txt jsonfile.json
"number": 303,"projectName
"queueId":8881,"result
[nukaNUKA@dev-machine csv]$
У меня есть сложный вложенный объект JSON, и, поскольку все неструктурировано, похоже, я не могу использовать JQ или JSONV или любой другой скрипт Python (в качестве данных то, что я ищу, хранится в массивах, содержащих 1 словарную запись (ключ = значение) с одинаковыми именами ключей для того, что я ищу (например: { "parameters": [ { "name": "jobname", "value": "shenzi" }, { "name": "pipelineVersion", "value": "1.2.3.4" }, ...so on..., ... ]
), и индекс для имени задания и pipelineVersion или аналогичных имен параметров не находится в одном и том же месте индекса [ X ] во всех имеющихся у меня записях JSON.
В худшем случае , я могу добавить условные проверки, чтобы увидеть, совпадает ли ключ в каждом индексе, имя задания и т. д., а затем я получаю те поля, которые я ищу, но тогда есть сотни таких полей, которые мне нужны Хватать. Я не хочу жестко их кодировать, если это возможно.
Я думал, что поскольку моя запись JSON для каждой строки, я могу просто написать классные шаблоны (уродливые, я знаю), но, по крайней мере, тогда мне не нужно беспокоиться об условном коде или просто использовать BASH / sed / tr / cut power, чтобы получить что мне нужно, но похоже, что egrep -f or -o ...
не работает, как показано выше.
Пример объекта BLOB-объекта JSON (из одного задания Jenkins). В одной коллекции JenkinsJobsBuild в MongoDB есть разные записи JSON для задания сборки Jenkins (каждая из которых имеет разные структуры JSON, параметры и т. Д.). См. Прикрепленный образец объекта BLOB-объекта JSON.
{
"_id": {
"$oid": "5120349es967yhsdfs907c4f"
},
"actions": [
{
"causes": [
{
"shortDescription": "Started by an SCM change"
}
]
},
{
},
{
"oneClickDeployPossible": false,
"oneClickDeployReady": false,
"oneClickDeployValid": false
},
{
},
{
},
{
},
{
"cspec": "element * ...\/MyProject_latest_int\/LATESTnelement * ...\/MyProject_integration\/LATESTnelement \/vobs\/some_vob\/gigi \/main\/myproject_integration\/MyProject_Slot_0_maint_int\/LATESTnelement * ...\/myproject_integration\/LATESTnelement \/vobs\/some_vob \/main\/LATEST",
"latestBlsOnConfiguredStream": null,
"stream": null
},
{
},
{
"parameters": [
{
"name": "CLEARCASE_VIEWTAG",
"value": "jenkins_MyProject_latest"
},
{
"name": "BUILD_DEBUG",
"value": false
},
{
"name": "CLEAN_BUILD",
"value": true
},
{
"name": "BASEVERSION",
"value": "7.4.1"
},
{
"name": "ARTIFACTID",
"value": "lowercaseprojectname"
},
{
"name": "SYSTEM",
"value": "myprojectSystem"
},
{
"name": "LOT",
"value": "02"
},
{
"name": "PIPENUMBER",
"value": "7.4.1.303"
}
]
},
{
},
{
},
{
"parameters": [
{
"name": "DESCRIPTION_SETTER_DESCRIPTION",
"value": "lowercaseprojectname_V7.4.1.303"
}
]
},
{
},
{
},
{
},
{
}
],
"artifacts": [
],
"building": false,
"builtOn": "servername",
"changeSet": {
"items": [
{
"affectedPaths": [
"vobs\/some_vob\/myproject\/apps\/app1\/Java\/test\/src\/com\/giga\/highlevelproject\/myproject\/schedule\/validation\/SomeActivityTest.java"
],
"author": {
"absoluteUrl": "http:\/\/11.22.33.44:8080\/user\/hitj1620",
"fullName": "name1, name2 A"
},
"commitId": null,
"date": {
"$numberLong": "1489439532000"
},
"dateStr": "13\/03\/2017 21:12:12",
"elements": [
{
"action": "create version",
"editType": "edit",
"file": "vobs\/some_vob\/myproject\/apps\/app1\/Java\/test\/src\/com\/giga\/highlevelproject\/myproject\/schedule\/validation\/SomeActivityTest.java",
"operation": "checkin",
"version": "\/main\/MyProject_latest_int\/2"
}
],
"msg": "",
"timestamp": -1,
"user": "user111"
}
],
"kind": null
},
"culprits": [
{
"absoluteUrl": "http:\/\/11.22.33.44:8080\/user\/nuka1620",
"fullName": "nuka, Chuck"
}
],
"description": "lowercaseprojectname_V7.4.1.303",
"displayName": "#303",
"duration": 525758,
"estimatedDuration": 306374,
"executor": null,
"fullDisplayName": "MyProject \u00bb MyProject-build #303",
"highlevelproject_metrics_source_url": "http:\/\/11.22.33.44:8080\/job\/MyProject\/job\/MyProject-build\/303\/\/api\/json",
"id": "303",
"keepLog": false,
"number": 303,
"projectName": "MyProject-build",
"queueId": 8201,
"result": "SUCCESS",
"timeToRepair": null,
"timestamp": {
"$numberLong": "1489439650307"
},
"url": "http:\/\/11.22.33.44:8080\/job\/MyProject\/job\/MyProject-build\/303\/"
}
2 ответа
Когда регулярные выражения находятся в файле, вам не нужно избегать двойных кавычек; вам не нужно бороться, чтобы ваши двойные кавычки миновали оболочку.
"number":.*"projectName
"projectName":.*,"queueId
"queueId":.*,"result
"result":".*$
Когда это исправлено, я получаю:
$ egrep -o -f egrep-pattern.txt jsonfile.json
"number": 303,"projectName
"queueId":8881,"result
$
Проблема теперь, я думаю, в том, что вы использовали projectName
с первым шаблоном, поэтому у других нет возможности сопоставить его. Измените шаблоны, чтобы читать до запятой, и вы можете получить лучшие результаты:
"number":[^,]*
"projectName":[^,]*
"queueId":[^,]*
"result":".*$
Дает:
"number": 303
"projectName": "giga"
"queueId":8881
"result":"SUCESS"}
Вы можете попытаться быть более деликатным, но быстро достигнете точки, когда инструмент, поддерживающий JSON, станет более разумным. Например, запятые в строковом значении могут испортить измененные регулярные выражения. (Так что, если бы проект назывался «Гига, если бы не Тера», у вас были бы проблемы.)
Соответствие более общему имени JSON: обозначение значения
Если вы ищете простые объекты "key":"quoted value"
, вы можете использовать следующую команду grep -E
(также известную как egrep
):
grep -Eoe '"[^"]+":"((\\(["\\/bfnrt]|u[0-9a-fA-F]{4}))|[^"])*"' data
Учитывая данные, подобные JSON (в файле с именем data
):
{"key1":"value","key2":"value2 with \"quoted\" text","key3":"value3 with \\ and \/ and \f and \uA32D embedded"}
Этот скрипт производит:
"key1":"value"
"key2":"value2 with \"quoted\" text"
"key3":"value3 with \\ and \/ and \f and \uA32D embedded"
Вы можете обновить его для обработки практически любого действительного JSON "key":value
, используя:
grep -Eoe '"[^"]+":(("((\\(["\\/bfnrt]|u[0-9a-fA-F]{4}))|[^"])*")|true|false|null|(-?(0|[1-9][0-9]*)(\.[0-9]+)?([eE][-+]?[0-9]+)?))' data
С новым файлом data
, содержащим:
{"key1":"value","key2":"value2 with \"quoted\" text"}
{"key3":"value3 with \\ and \/ and \f and \uA32D embedded"}
{"key4":false,"key5":true,"key6":null,"key7":7,"key8":0,"key9":0.123E-23}
{"key10":10,"key11":3.14159,"key12":0.876,"key13":-543.123}
Скрипт производит:
"key1":"value"
"key2":"value2 with \"quoted\" text"
"key3":"value3 with \\ and \/ and \f and \uA32D embedded"
"key4":false
"key5":true
"key6":null
"key7":7
"key8":0
"key9":0.123E-23
"key10":10
"key11":3.14159
"key12":0.876
"key13":-543.123
Вы можете следить за железнодорожными диаграммами в схеме спецификации JSON на http://json.org, чтобы увидеть, как я создал регулярное выражение. .
Его можно было бы улучшить, разумно добавив [[:space:]]*
в местах, где пробелы разрешены, но не требуются - перед ключевой строкой, перед двоеточием, после двоеточия (вы можете добавить его и после значения, но вы, вероятно, не не хочу этого).
Еще одно упрощение, которое я сделал, заключается в том, что ключ не позволяет использовать различные escape-символы, которые делает строка значения. Вы можете повторить это.
И, конечно же, это работает только для пар «лист» имя: значение; если значение само по себе является объектом {…}
или массивом […]
, это не обрабатывает значение в целом.
Однако это просто подчеркивает, что это очень быстро становится беспорядочным, и вам было бы лучше использовать специальный инструмент запросов JSON. Одним из таких инструментов является jq
, как упоминалось в комментарии к основному запросу.
Сложный JSON blob, который у меня был, был взят из Jenkins (например, Jenkins job Rest API data), который у меня был в базе данных MongoDB.
Чтобы получить его из MongoDB, я использовал команду mongoexport для успешного создания блоба JSON (не в формате JsonArray или в формате Pretty).
#/bin/bash
server=localhost
collectionFile=collections.txt
## Generate collection file contains all collections in the Jenkins database in MongoDB.
( set -x
mongo "mongoDbServer.company.com/database_Jenkins" --eval "rs.slaveOk();db.getCollectionNames()" --quiet > ${collectionFile}
)
## create collection based JSON files
for collection in $(cat ${collectionFile} | sed -e 's:,: :g')
do
mongoexport --host ${server} --db ${db} --collection "${collection}" --out ${exportDir}/${collection}.json
##mongoexport --host ${server} --db ${db} --collection "${collection}" --type=csv --fieldFile ~/mongoDB_fetch/get_these_csv_fields.txt --out ${exportDir}/${collection}.csv; ## This didn't work if you have nested fields. fieldFile file was just containing field name per line in a particular xyz.IndexNumber.yyy format.
done
Пробовал встроенную команду mongoexport --type=csv
с полями -f
, чтобы поймать topfield.0.subField, field2, field3.7.parameters.7..
, ничего не сработало.
PS : number
после знака .
указывает, как вы определяете индексы, если собираетесь создать файл CSV и использовать поля (обязательные) с помощью команды mongoexport
. .
Поскольку вся моя структура JSON была неструктурированной (в прошлом происходили скачки / обновления версии Jenkins, и данные о задании имели разную структуру), я попробовал этот последний трюк sed
(поскольку данные JSON для каждой записи были в каждой отдельной строке ).
Эта команда sed
(как показано ниже) предоставит вам все ключи и их значения (в формате ключ = значение ). на строку на уровне поля LEAF ключ = значение почти любого большого двоичного объекта JSON / по крайней мере из большого двоичного объекта Jenkins JSON. Получив эту информацию, вы можете передать вывод этой команды во временный файл, затем прочитать всю часть значения (после метки =
) и создать свой CSV-файл в соотв. ДА, вы должны отсортировать его, чтобы поля вашего CSV-файла поддерживались в соответствии с именами заголовков и, таким образом, значения вставлялись в правый столбец / поле. Я вычислил имена полей из всех различных коллекций JSON-файла сгенерированных имен ключей временного ключа = значения. Затем прочтите все временные файлы коллекции и добавьте значения в соотв. в окончательный CSV-файл под соответствующим заголовком / полем / столбцом.
Хорошо, это странное решение, но, по крайней мере, это решение - в одной строке .
cat myJenkinsJob.json | sed "s/{}//g;s/,,*/,/g;s/},\"/\n/g;s/},{/\n/g;s/\([^\"a-zA-Z]\),\"/\1\n/g;s/:\[{/\n/g;s/\"name\":\"//g;s/\",\"value//g;s/,\"/\n/g;s/\":\"*/=/g;s/\"//g;s/[\[}\]]//g;s/[{}]//g;s/\$[a-zA-Z][a-zA-Z]*=//g"|grep "=" | sed "s/,$//"|egrep -v "=-|=$|=\[|^_class="
Подправьте это соотв. к вашему собственному решению для части sed
, если ваш JSON-объект показывает вам забавных персонажей, которые вам не нужны. Порядок действий sed важен ниже. Я также исключаю любые избыточные переменные (которые мне сейчас не нужны, например: BLOB-объект JSON содержал значения _class = "..."), поэтому я исключаю их через egrep -v
после последнего { {X2}} труба.
Похожие вопросы
Новые вопросы
json
JSON (объектная нотация JavaScript) - это сериализуемый формат обмена данными, предназначенный для машинного и человеческого чтения. Не используйте этот тег для собственных объектов JavaScript или литералов объектов JavaScript. Прежде чем задать вопрос, проверьте свой JSON с помощью валидатора JSON, такого как JSONLint (https://jsonlint.com).