0

I have a text file with a sequence of lines repeating multiple times. For example:

param id: 0
value: 2
description: "hello"

param id: 1
value: 3
description: "world"

I want to move description above value and change param id to one value higher, like param id 1 instead of 0. I want to do this using scripting. Can somebody help me with the commands that can achieve this?

don_crissti
  • 82,805
sss07
  • 1

4 Answers4

1

As has already been suggested by @MelBursian in the comments, I also would favor awk over sed.

awk '
    BEGIN { OFS=FS=": " }
    {
        if ($1 == "param id") {
            $2 += 1;
        }
        if ($1 == "value") {
            val=$0; getline;
            print; print val;
            next;
        }
        print;
    }
' file
Guido
  • 4,114
0

This will switch all lines that start with "value: " with the respective next line:

sed '/^value: /{N;s/^\(.*\)\n\(.*\)$/\2\n\1/}'

Expanation:

  • /^value: / { ... } will execute the commands in braces (here the fake ...) only for the lines that match the regular expression "^value: "
  • N will append the next line to the pattern space. So we can operate on two lines joined by a newline from here on.
  • s/^\(.*\)\n\(.*\)$/\2\n\1/ will switch the text before the newline with the text after the newline.
    • s/something/else/ is the replace command that will replace "something" with "else"
    • ^\(.*\)\n\(.*\)$ will match any text from the beginning of the pattern space to a new line char and save it as expression one, and then all further chars to the end of the pattern space will be saved as expression two
    • \2\n\1 will put expression two followed by a newline and then followed by expression one as the replacement
Jeff Schaller
  • 67,283
  • 35
  • 116
  • 255
Lucas
  • 2,845
0

To increment a value with sed is extremly not recommended. it's not the correct tool for such a job. But if it has to be sed, this works only with GNU sed.

sed -rn '/^param/{s/(.*)([0-9]+)/echo \1$((\2+1))/e;p;n;h;n;p;x;p;n;p}' file

  • -r activates extended regular expressions.
  • -n disables sed's auto-printing.
  • /^param/ search for a line starting with the pattern param.
    • s/(.*)([0-9]+)/echo \1$((\2+1))/e now do a search/replace in that line. Search for number ([0-9]+) and replace it with echo \1$((\2+1)), which then is executed. e in s///e is the modificator that executed the matched pattern in a shell.
    • p; then prints the altered line.
    • n; loads the next line in the pattern space (the value line).
    • h; copies that line into the hold space.
    • n;p; loads the next line (the description line) and prints it.
    • x; exchanges the pattern and the hold space.
    • p; prints that line.
    • n;p loads the next line (the empty line) and prints it.

The output with your example input:

param id: 1
description: "hello"
value: 2

param id: 2
description: "world"
value: 3
chaos
  • 48,171
0

The line moving is most easily done with POSIX ex; the numeric increment is most easily done with awk. Fortunately, ex allows you to filter specific lines through external tools:

printf %s\\n 'g/description/m-2' 'g/param id/.!awk "++\$NF"' x | ex file

Translated into English, the first command is "Move all lines that contain the word 'description' one line up."

(There's a 2 there because, more literally translated, it's "Move these lines to the point just after the lines two lines up.")

The second is, "Filter each line that contains 'param id' through awk."

The awk command is, "Increment the final field of the line (and print the line, unless the result happens to be zero. :)"

x is "Save and exit."

Wildcard
  • 36,499