Как найти конкретное значение на основе совпадения поискового значения

По сути, это вопрос захвата тех частей, которые вам нужны, и отбрасывания тех, которые вам не нужны. Например, используя sed, вы можете захватить целочисленное значение Successи скопировать его в область хранения(h ), извлекая и добавляя его(G)к захваченным цифрам Completed. ] строка:

sed -nE \
  -e '/Success/ {s/.* ([0-9]+).*/\1/; h;}' \
  -e '/Completed/{G; s/.*T_init = ([0-9]+)\.00 degC & T_sink = ([0-9]+).*\n/\1 \2 /; p;}
' terminal_output.txt

Perl предоставляет несколько более выразительный синтаксис, который, ИМХО, более удобочитаем.:

perl -lne '
  our $a = $1 if /Success.*?(\d+)/; print join " ", /(\d+)\.\d+/g, $a if /Completed/
' terminal_output.txt

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

25 35 128
30 40 307
5
22.04.2020, 19:24
9 ответов

Это может быть полезно.

grep -B 6 AVAILABLE db_systems.txt | grep db-unique-name
0
19.03.2021, 02:26

Попробуйте это,

Использованиеgrep:

 grep -B6 AVAILABLE file | grep db-unique-name
 "db-unique-name": "p00z5bj_iad2bj",
  • BПечатать NUM строк начального контекста перед сопоставлением строк.

Использованиеawk:

 awk '{a[++i]=$0;}/AVAILABLE/{print a[NR-6];}' file
 "db-unique-name": "p00z5bj_iad2bj",
3
19.03.2021, 02:26

Вы можете попробовать это с GNUawk:

awk -F',' 'BEGIN { RS = "--" } /"lifecycle-state": "AVAILABLE"/ {  gsub("^[[:blank:]]*", "", $1);  print $1 }' file

Выход:

"db-unique-name":"p00z5bj_iad2bj"
5
19.03.2021, 02:26

Это должно работать:

$ awk '$1=="\"db-unique-name\":"{name=$2} 
       $1=="\"lifecycle-state\":" && $2 ~ /AVAILABLE/ {print name}' systems.txt 
"p00z5bj_iad2bj",

Или, если вам нужна вся строка db-unique-name, попробуйте:

$ awk '$1=="\"db-unique-name\":"{name=$0} 
       $1=="\"lifecycle-state\":" && $2 ~ /AVAILABLE/ {print name}' systems.txt 
     "db-unique-name": "p00z5bj_iad2bj",
3
19.03.2021, 02:26

Если вы имеете дело с данными в формате JSON, (фрагменты выглядят так ), вам обязательно следует взглянуть на jq, который является довольно полезным инструментом для таких данных.

Если ваши данные выглядят так

{
    "db-unique-name": "p00z5bj_iad2bj",
      "db-workload": "OLTP",
      "defined-tags": {},
      "freeform-tags": {},
      "id": "dfadfasfsadfasdfasdf",
      "lifecycle-details": null,
      "lifecycle-state": "AVAILABLE"
}
{
      "db-unique-name": "p00u5bh_iad2bj",
      "db-workload": "OLTP",
      "defined-tags": {},
      "freeform-tags": {},
      "id": "asdfsadfasdfasfd",
      "lifecycle-details": "Resource was terminated at the backend.",
      "lifecycle-state": "FAILED"
}
{
      "db-unique-name": "p00u5bh_iad2bj",
      "db-workload": "OLTP",
      "defined-tags": {},
      "freeform-tags": {},
      "id": "asdfasdfasdf",
      "lifecycle-details": "Resource was terminated at the backend.",
      "lifecycle-state": "FAILED"
}

то это jqутверждение

jq 'select(."lifecycle-state" == "AVAILABLE") |."db-unique-name" ' < db_systems.txt

выводит

"p00z5bj_iad2bj"

Однако, если ваш файл на самом деле выглядит как пример, который вы привели (с --в качестве разделителей и без нотации объекта {} ), тогда решение awkможет быть проще, его довольно сложно впихнуть не -данные JSON в jq...

4
19.03.2021, 02:26

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

$ cat tst.awk
{
    gsub(/^[[:space:]]*"|"?,[[:space:]]*$/,"")
    tag = val = $0
    sub(/".*$/,"",tag)
    sub(/.*"/,"",val)
    f[tag] = val
}
/^--/ { prt() }
END { prt() }

function prt() {
    if ( f["lifecycle-state"] == "AVAILABLE" ) {
        print f["db-unique-name"]
    }
    delete f
}

$ awk -f tst.awk file
p00z5bj_iad2bj

Например:

$ cat tst.awk
BEGIN { OFS="," }
{
    gsub(/^[[:space:]]*"|"?,[[:space:]]*$/,"")
    tag = val = $0
    sub(/".*$/,"",tag)
    sub(/.*"/,"",val)
    f[tag] = val
}
/^--/ { prt() }
END { prt() }

function prt() {
    recNr++
    if ( (f["lifecycle-state"] == "FAILED") || ( (f["db-unique-name"] ~ /bh/) && (f["db-workload"] == "OLTP") ) ) {
        print recNr, f["lifecycle-details"], f["id"], f["db-unique-name"]
    }
    delete f
}

$ awk -f tst.awk file
2,Resource was terminated at the backend.,asdfsadfasdfasfd,p00u5bh_iad2bj
3,Resource was terminated at the backend.,asdfasdfasdf,p00u5bh_iad2bj
2
19.03.2021, 02:26

Предполагая, что поля базы данных -уникальное -имя и состояние жизненного цикла -являются обязательными и всегда выводятся в одном и том же порядке (, но не предполагается, что между ними всегда ровно 5 строк )я бы использовал:

cat db_systems.txt \
  | grep -E '"(db-unique-name|lifecycle-state)":' \
  | grep -B 1 '"AVAILABLE"' \
  | grep db-unique-name \
  | cut -d\" -f4

Идеально подходит для передачи в xargs, while read nameи т. д.

0
19.03.2021, 02:26

Если это фрагменты данных JSON, заверните их обратно в JSON и используйте инструмент JSON.

{ echo '{'; sed 's/^ *-- *$/"": ""} {/' db_systems.txt; echo '"": ""}'; } |
jq 'select(."lifecycle-state" == "AVAILABLE") |."db-unique-name" '

(jqзапрос Ганс -Мартин Моснер)

2
19.03.2021, 02:26

Это работает:

grep -e db-unique-name -e lifecycle-state.*AVAILABLE < filename | grep -B1 lifecycle-state.*AVAILABLE | grep db-unique-name

В отличие от использования -B6, это не предполагает наличие 6 строк между двумя интересующими строками.

(Конечно, во многих других ответах справедливо предлагалось использовать jq, что определенно является лучшим вариантом ).

0
19.03.2021, 02:26

Теги

Похожие вопросы