sed: How to add a key/value pair at the end of the section in INI file

chesschi yesterday at 15:03. 2 answers, 0 views
regex bash sed ini

In order to add a key/value pair at the end of the section in INI file, I would like to:

  1. Find the match section name and check if next square bracket (i.e. ^[) is available. If so, find the last occurrence of key/value pair within these lines (i.e. from match section name to next square bracket). Insert the key/value pair at the end of last occurrence of key/value pair.

  2. Append the key/value pair to the end of the file if next square bracket is not available.

For case (1), I can use sed to check if next square bracket is available, i.e.

sed -i -e "/^\[$section\]/,/^\[.*\]/ ..."

However, I have no idea how to match the last occurrence of key=value. The reason of matching the last occurrence (instead of adding ke/value pair just before next square bracket) is because I can choose to introduce newline or not before the new key/value pair in the INI file. For example, if I want to add key10=value10

[section1]
...
key8=value8
key9=value9
\n (could be multiple newline)
[section2]

It becomes

[section1]
...
key8=value8
key9=value9
\n (optional)
key10=value10
\n (could be multiple newline)
[section2]

Please could you kindly suggest how can I achieve this?

2 Answers


Wintermute 12/08/2014.

For the sake of completeness (and because sed hackery is mindbendy fun), you can do it with sed like this:

/^\[section1\]/,/^\[/ {
  x
  /^$/ !{ x; H }
  /^$/  { x; h }
  d
}
x
/^\[section1\]/ {
  s/\(\n\+[^\n]*\)$/\nkey10=value10\1/
  p
  x
  p
  x
  d
}
x
p

Put that in a file, say foo.sed, and run sed -n -f foo.sed foo.ini. Or, if you prefer,

sed '/^\[section1\]/,/^\[/ { x; /^$/ !{ x; H }; /^$/ { x; h; }; d; }; x; /^\[section1\]/ { s/\(\n\+[^\n]*\)$/\nkey10=value10\1/; p; x; p; x; d }; x' foo.ini

...as if it wasn't hard enough to read already.

This is fun with the hold buffer; the first bit matches all lines from [section1] to the beginning of the next section and puts then all in the hold buffer (and breaks out there). If we're not in that section, the rest swaps in the hold buffer, checks if section1 is in it, if so substitutes key10=value10 into it at the appropriate position, prints it, swaps the pattern space back, prints it, swaps the hold space back and deletes it (now the line after section1 is in the hold buffer, but we don't care about it anymore). The rest of the time, the pattern space is just swapped back and printed, so from there it works like cat.

EDIT: NeronLeVelu pointed out that this only works if there is a section after [section1] that the pattern range can match. Where this is not guaranteed, special handling for the last line is needed in case section1 hasn't been handled by then. This can do it:

$ {
  H
  x
  /^\[section1\]/ {
    s/\n\+$//
    a key10=value10
    x
  }
  x
  p
  d
}
/^\[section1\]/,/^\[/ {
  x
  /^$/ !{ x; H }
  /^$/  { x; h }
  d
}
x
/^\[section1\]/ {
  s/\(\n\+[^\n]*\)$/\nkey10=value10\1/
  p
  x
  p
  x
  d
}
x
p

This will handle the last line differently from the rest; it'll append it to the hold buffer, check if section1 still needs handling, if so append key10=value10 and swap back, then swap back again and print what is then the pattern space. This confusing bit of shunting means that if section1 is still in the hold buffer, then the hold buffer is printed, and otherwise the last line as it came in.

By this point, I feel compelled to point out that once a sed script has become this long, it is worth considering other options.


anubhava 12/08/2014.

You can use this awk:

awk -v sec='[section1]' -v kv='key10=value10' 'p && $1~/\[[^]]*\]/{p=0; print kv} 
           $1==sec{p=1} END{if (p) print kv} 1' file
[section1]
...
key8=value8
key9=value9

key10=value10
[section2]

HighResolutionMusic.com - Download Hi-Res Songs

1 Alan Walker

Diamond Heart flac

Alan Walker. 2018. Writer: Alan Walker;Sophia Somajo;Mood Melodies;James Njie;Thomas Troelsen;Kristoffer Haugan;Edvard Normann;Anders Froen;Gunnar Greve;Yann Bargain;Victor Verpillat;Fredrik Borch Olsen.
2 Sia

I'm Still Here flac

Sia. 2018. Writer: Sia.
3 Cardi B

Taki Taki flac

Cardi B. 2018. Writer: Bava;Juan Vasquez;Vicente Saavedra;Jordan Thorpe;DJ Snake;Ozuna;Cardi B;Selena Gomez.
4 Little Mix

Woman Like Me flac

Little Mix. 2018. Writer: Nicki Minaj;Steve Mac;Ed Sheeran;Jess Glynne.
5 Halsey

Without Me flac

Halsey. 2018. Writer: Halsey;Delacey;Louis Bell;Amy Allen;Justin Timberlake;Timbaland;Scott Storch.
6 Lady Gaga

I'll Never Love Again flac

Lady Gaga. 2018. Writer: Benjamin Rice;Lady Gaga.
7 Bradley Cooper

Shallow flac

Bradley Cooper. 2018. Writer: Andrew Wyatt;Anthony Rossomando;Mark Ronson;Lady Gaga.
8 Bradley Cooper

Always Remember Us This Way flac

Bradley Cooper. 2018. Writer: Lady Gaga;Dave Cobb.
9 Kelsea Ballerini

This Feeling flac

Kelsea Ballerini. 2018. Writer: Andrew Taggart;Alex Pall;Emily Warren.
10 Mako

Rise flac

Mako. 2018. Writer: Riot Music Team;Mako;Justin Tranter.
11 Dewain Whitmore

Burn Out flac

Dewain Whitmore. 2018. Writer: Dewain Whitmore;Ilsey Juber;Emilio Behr;Martijn Garritsen.
12 Avril Lavigne

Head Above Water flac

Avril Lavigne. 2018. Writer: Stephan Moccio;Travis Clark;Avril Lavigne.
13 Khalid

Better flac

Khalid. 2018. Writer: Charlie Handsome;Jamil Chammas;Denis Kosiak;Tor Erik Hermansen;Mikkel Stoleer Eriksen;Khalid.
14 Lady Gaga

Look What I Found flac

Lady Gaga. 2018. Writer: DJ White Shadow;Nick Monson;Mark Nilan Jr;Lady Gaga.
15 Deep Chills

Run Free flac

Deep Chills. 2018.
16 Dynoro

In My Mind flac

Dynoro. 2018. Writer: Georgi Kay;Feenixpawl;Ivan Gough.
17 Charli XCX

1999 flac

Charli XCX. 2018. Writer: Charli XCX;Troye Sivan;Leland;Oscar Holter;Noonie Bao.
18 NCT 127

Regular (English Version) flac

NCT 127. 2018.
19 Lukas Graham

Love Someone flac

Lukas Graham. 2018. Writer: Don Stefano;Morten "Rissi" Ristorp;Morten "Pilo" Pilegaard;Jaramye Daniels;James Alan;David LaBrel;Lukas Forchhammer Graham.
20 Rita Ora

Let You Love Me flac

Rita Ora. 2018. Writer: Rita Ora.

Language

Popular Tags