0

Assuming the following file structure:

[topic1]
key1 = "value1"
key2 = "value2"
[topic2]
key1 = "value3"
.
.
.

How can I extract value2 from key2 from topic1 to the shell?I'm used to use jq to read json file and get key-value entries but I have no idea to extract the key value in this situation.

André Guerra
  • 486
  • 7
  • 22

4 Answers4

1

Currently I have the following script working:

sed -nr "/^\[topic1\]/ { :l /^key2[ ]*=/ { s/.*=[ ]*//; p; q;}; n; b l;}" file | tr -d '"'

Seems to work but I was looking for a more simplified way to do this.

André Guerra
  • 486
  • 7
  • 22
  • Include that in your question to improve your question which is supposed to contain a [mcve] including concise, testable sample input plus expected output plus what yopu'd tried so far (i.e. the script in this "answer"), don't post it separately as an answer. See [ask] if that's not clear. – Ed Morton Mar 01 '19 at 14:18
  • 1
    That's not bad, except that if the desired key is not present in the given topic, it continues the search in the following topics. – Armali Mar 01 '19 at 14:19
1

all sed -

EDIT - I removed the specificity of which topic needed to follow topic1. Now any new [topic will end the range, so order shouldn't matter.

sed -En '/^\[topic1\]/,/^\[topic/ { /^key2\s*=/ { s/^.*=\s*"([^"]+)".*/\1/; p; } }' 

Breakout:

sed -En says use extended matching but don't print anything unless requested.

/^\[topic1\]/,/^\[topic/ { ... }
says do the stuff between the braces only between the section headers for topic1 and topic2 (inclusive).

Within that,
/^key2\s*=/ { ... } says do the stuff between these braces only on the key2 lines.

Then, once you've found the key2 between topic1 and the next topic,
s/^.*=\s*"([^"]+)".*/\1/; says replace the whole line with just the value part between the quotes, and then print the result.

Formatted:

sed -En '
  /^\[topic1\]/,/^\[topic/ {
    /^key2\s*=/ { 
      s/^.*=\s*"([^"]+)".*/\1/;
      p;
    }
  }
'

Remove the ;'s and that will work for non-GNU sed as well, I think.

Paul Hodges
  • 13,382
  • 1
  • 17
  • 36
1
$ awk -F' *= *"|"$' '
    gsub(/^\[|]$/,"") { topic=$0; next }
    (topic=="topic1") && ($1=="key2") { print $2 }
' file
value2
Ed Morton
  • 188,023
  • 17
  • 78
  • 185
0

topics are not ordered, so how to define only one?

Just specify /^\[/ (the beginning of a following topic) as the second pattern (end) of the address range, e. g.:

sed -n '/^\[topic1]/,/^\[/s/key2 = "\(.*\)"/\1/p' file
Armali
  • 18,255
  • 14
  • 57
  • 171