Как извлечь текст между двумя шаблонами с помощью sed / awk - PullRequest
1 голос
/ 24 сентября 2019

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

{"version":"4.9.123M","info":{"version":[2034.2],"description":""},"status":"OK"}

Ожидаемый результат:

2034.2

Этот номер версии не всегда будет одинаковым, но остальныестрока должна.

Я пытался работать с sed, но я новичок в этом и потерпел неудачу:

 sed -e 's/version":[\(.*\),"description/\1/'

вывод:

sed: -e expression #1, char 35: unterminated `s' command

Я думаю, проблема в том, чтов строке слишком много специальных символов, и я не очень хорошо написал команду.

Ответы [ 4 ]

6 голосов
/ 24 сентября 2019

Поскольку это JSON, для его использования необходимо использовать инструменты, поддерживающие JSON.Если вы предпочитаете, например, awk, вы можете использовать расширение JSON для GNU awk.Это небольшое руководство.

Сначала загрузите и скомпилируйте соответствующие версии GNU awk, Gawkextlib и gawk-json .Это довольно просто, на самом деле, просто ./configure и make.Затем напишите некоторый код:

awk '
@load "json"                                 # enable json extension
{
   lines=lines $0                            # read json file records and buffer to var lines
   if(json_fromJSON(lines,data)==1) {        # once the json is complete
       for(i in data["info"]["version"])     # that seems to be an array so all elements
           print data["info"]["version"][i]  # are outputed
       lines=""                              # once done with the first json object
   }                                         # reset the var for more lines
}' file

Выведите на этот раз:

2034.2

Объясните немного больше:

Структура файла JSON можетварьируются от одной строки до нескольких строк, например:

{"version":"4.9.123M","info":{"version":[2034.2],"description":""},"status":"OK"}

или:

{
  "version": "4.9.123M",
  "info": {
    "version": [
      2034.2
    ],
    "description": ""
  },
  "status": "OK"
}

, поэтому нам нужно буферизовать строки JSON с помощью lines=lines $0, пока не появится целый действительный объектв переменной lines.Мы используем функцию расширения json_fromJSON(), чтобы определить эту достоверность в if(json_fromJSON(lines,data)==1).При проверке объект распутывается и сохраняется в массиве data.Для этого конкретного объекта структура массива:

data["version"]="4.9.123M"
data["info"]["version"][1]="2034.2"
data["info"]["description"]=""
data["status"]="OK"

Мы могли бы исследовать объект и получить некоторый вывод о нем с помощью этой функции сканирования рекурсивного массива:

awk '
@load "json"
function scan(a,p,    q) {           # a is array, p path to it, q is qnd *
    if(isarray(a))
        for(i in a) {
            q=p (p==""?"":"->") i
            scan(a[i],q)
        }
    else
        print p ":" a
}
{
   lines=lines $0
   if(json_fromJSON(lines,data)==1)
       scan(data)                    #
}' file.json

Вывод:

status:OK
version:4.9.123M
info->version->1:2034.2
info->description:

*) quick'n dirty

Вот краткий пример того, как вывести JSON из массива: https://stackoverflow.com/a/58109715/4162356

2 голосов
/ 24 сентября 2019

Если версия всегда заключена в [] и в строке нет других [или], вы можете попробовать эту логику

STR='{"version":"4.9.123M","info":{"version":[2034.2],"description":""},"status":"OK"}'
echo $STR | awk -F'[' '{print $2}' | awk -F']' '{print $1}'
0 голосов
/ 24 сентября 2019

Это должно сделать:

STR='{"version":"4.9.123M","info":{"version":[2034.2],"description":""},"status":"OK"}'
echo "$STR" | awk -F'[][]' '{print $2}'
2034.2
0 голосов
/ 24 сентября 2019

Simplest Way

Попробуйте grep, когда хотите извлечь простые тексты

 echo "{"version":"4.9.123M","info":{"version":[2034.2],"description":""},"status":"OK"}"| grep -o "\[.*\]" | sed -e 's/\[\|\]//g'
...