5

I need help in finding "db-unique-name" that has lifecycle-state": "AVAILABLE".

cat db_systems.txt

     "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",
    enter code here

Tried "db-unique-name" value based on "lifecycle-state": "AVAILABLE". the following , but it gives wrong value

cat db_systems.txt  |  egrep -A -6  "lifecycle-state|AVAILABLE" | grep  db-unique-name
"db-unique-name": "p00u5bh_iad2bj",
"db-unique-name": "p00u5bh_iad2bj",

I also tried this, but it is listing all of them

cat db_systems.txt |  awk -F";" '{for(i=1;i<=NF;i++){if ($i ~ /AVAILABLE|db-unique-name/){print $1}}}' | grep db-unique-name
"db-unique-name": "p00z5bj_iad2bj",
"db-unique-name": "p00u5bh_iad2bj",
"db-unique-name": "p00u5bh_iad2bj",
3
  • Add the expected output to your question. Commented Apr 22, 2020 at 16:06
  • 3
    Is that the actual and original file that you're working with, or have you modified the file from some JSON original? It would be easier to work with a JSON document (like the output of oci network vcn list or similar command would be), and the format looks as if it could have been JSON from the start.
    – Kusalananda
    Commented Apr 22, 2020 at 16:56
  • Following @Kusalananda , jq generally rocks at parsing json from the command line. Commented Apr 23, 2020 at 16:35

9 Answers 9

5

You can try this with GNU awk:

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

Output:

"db-unique-name":"p00z5bj_iad2bj"
0
4

If you're dealing with JSON formatted data (the fragments look like it) you should certainly have a look at jq which is a pretty useful tool for such data.

If your data looks like this

{
    "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"
}

then this jq statement

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

will output

"p00z5bj_iad2bj"

However, if your file actually looks like the example you've given (with -- as separators and no {} object notation) then the awk solution might be easier, it's somewhat difficult to shove non-JSON data into jq...

4
  • 1
    Could you give an example showing how jq would produce the desired output from the example input? Without such an example, this isn't really answering the question and should probably just be a comment.
    – terdon
    Commented Apr 22, 2020 at 16:44
  • According to this comment this is the actual data and I don't understand why the question was closed there.
    – Freddy
    Commented Apr 22, 2020 at 16:58
  • Oh I did not see that, sorry. Yes, in that case jq will not fit the bill. Commented Apr 22, 2020 at 17:04
  • @Freddy The data seems to come from an Oracle Virtual Cloud Network (vcn) command. These commands output JSON.
    – Kusalananda
    Commented Apr 23, 2020 at 16:50
3

Try this,

Using grep:

 grep -B6 AVAILABLE file | grep db-unique-name
 "db-unique-name": "p00z5bj_iad2bj",
  • B Print NUM lines of leading context before matching lines.

Using awk:

 awk '{a[++i]=$0;}/AVAILABLE/{print a[NR-6];}' file
 "db-unique-name": "p00z5bj_iad2bj",
2
  • 1
    perhaps worth explaining what the -B flag does Commented Apr 23, 2020 at 14:55
  • @SteveLorimer updated...
    – Siva
    Commented Apr 23, 2020 at 18:12
3

This should work:

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

Or, if you want the entire db-unique-name line, try:

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

With this approach of first creating an array, f[] below, that maps each elements name to its value you can access every field by it's name and so create complex conditions and print fields in any order:

$ 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

For example:

$ 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

If these are extracts of JSON data, wrap them back into JSON and use a JSON tool.

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

(jq query by Hans-Martin Mosner)

0

This can be helpful.

grep -B 6 AVAILABLE db_systems.txt | grep db-unique-name
0

Assuming that the db-unique-name and lifecycle-state fields are mandatory and are always output in the same order (but not assuming that there are always exactly 5 lines in between) I'd use:

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

Which is perfect for piping into xargs, while read name, etc.

0

This works:

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

Unlike using -B6, this does not assume there are 6 line between the two lines of interest.

(Of course, many other responses rightly suggested using jq, which is definitely the better option).

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .