0

I need to use awk to increase the version number by one in the line after a unique string.

Original:

<key>UniqueKey</key>
<string>100</string>

Desired output

<key>UniqueKey</key>
<string>101</string>

Unfortunately "string" is not unique in the file, so I have to modify the line after the unique "key" string. I need to take the number, whatever it may be, and increase it by one. The command will be running in a virtual workspace that gets deleted each time, so a simple awk command would be preferred.

3 Answers3

2
$ awk -F'[<>]' '$3=="UniqueKey"{n=NR} 
   n && NR==n+1 && $2=="string"{sub($3,$3+1)}1' file

<key>UniqueKey</key>
<string>101</string>
karakfa
  • 66,216
  • 7
  • 41
  • 56
0

This looks remarkably like an XML file. It is strongly recommended to use XML-related tools for this job such as xmlstarlet.

Assuming a given input file of the form :

<header>
  <node>
    <key>UniqueKey</key>
    <foo />
    <string>100</string>
  </node>
  <node>
    <key>UniqueKey</key>
    <string>101</string>
    <string>200</string>
  </node>
</header>

Then the following command will update as requested :

$ xmlstarlet ed -u '//key[text()="UniqueKey"]/following-sibling::string[1]' \
                -x '(text()+1)' file.xml

This does the following :

  • ed: enter editing mode
  • -u <xpath>: update the nodes matched by xpath

    • //key: select any node with name key
    • //key[text()="UniqueKey"]: select any node with the name key and value "UniqueKey"
    • //key[text()="UniqueKey"]/following-sibling::string: pick the first 'string' siblings of key that follows key
  • -x '(text()+1)' : update the selected nodes value by the expression text()+1

The output is then given by :

<?xml version="1.0"?>
<header>
  <node>
    <key>UniqueKey</key>
    <foo/>
    <string>101</string>   # change
  </node>
  <node>
    <key>UniqueKey</key>
    <string>102</string>   # change
    <string>200</string>   # no change
  </node>
</header>

Or if it realy has to be the next node, then you need to play a trick with concat and substring as xpath-1.0 does not have if conditions. More details here

$ xmlstarlet ed -u '//key[text()="UniqueKey"]/following-sibling::*[1]' \
                -x 'substring(text()+1,1,number(name()="string")*string-length(text()+1))' file.xml

<?xml version="1.0"?>
<header>
  <node>
    <key>UniqueKey</key>
    <foo/>
    <string>100</string>   # no change
  </node>
  <node>
    <key>UniqueKey</key>
    <string>102</string>   # change
    <string>200</string>   # no change
  </node>
</header>
kvantour
  • 25,269
  • 4
  • 47
  • 72
0
$ awk -F'[<>]' '$2=="string" && p3=="UniqueKey" { sub(/>[^<]+/,">"$3+1) } {p3=$3} 1' file
<key>UniqueKey</key>
<string>101</string>
Ed Morton
  • 188,023
  • 17
  • 78
  • 185
  • While this answer is probably correct and useful, it is preferred if you include some explanation along with it to explain how it helps to solve the problem. This becomes especially useful in the future, if there is a change (possibly unrelated) that causes it to stop working and users need to understand how it once worked. – Erty Seidohl May 25 '18 at 16:08
  • You are wrong. Trivial solutions that anyone can figure out with a brief glance at google an/d/or a man page are best left as-is since people learn a lot more from doing that than just how one script works. – Ed Morton May 25 '18 at 16:20
  • Hi Ed. Obviously you have a lot more karma than me so I'll defer. I leave this on only-code answers to encourage richer answers. What's trivial to us experienced folks might be non-trivial to someone just starting out :) – Erty Seidohl May 25 '18 at 16:24
  • Don't post comments on only-code answers that you don't understand, it just clutters up the site and wastes peoples time. The tool flags **possible** low quality answers when it sees code-only answers, it's a highly flawed approach and it's up to people who understand the code to decide if the answer is low quality or not - there's nothing fundamentally wrong with code-only answers and code only does not mean low quality. – Ed Morton May 25 '18 at 16:29