mozzbozz
mozzbozz

Reputation: 3143

How to decrement (subtract) number in file with sed

I've got some source code like the following where I call a function in C:

void myFunction (
    &((int) table[1, 0]),
    &((int) table[2, 0]),
    &((int) table[3, 0])
);

...the only problem is that the function has >300 parameters (it's an auto-generated wrapper for initialising and calling a whole module; it was given to me and I cannot change it). And as you can see: I began accessing the array with a 1 instead of a 0... Great times, modifying all the 300 parameters, i.e. decrasing 300 x the x-coordinate of the array, by hand.

The solution I am looking for is how I could force sed to to do the work for me ;)

EDIT: Please note that the syntax above for accessing a two-dimensional array in C is wrong anyway! Of course it should be [1][0]... (so don't just copy-and-paste ;))

Upvotes: 1

Views: 2871

Answers (2)

Tom Fenech
Tom Fenech

Reputation: 74605

Here's another way you could do it, using Perl:

perl -pe 's/(table\[)(\d+)(,)/$1.($2-1).$3/e' file.c

This uses the e modifier to execute an expression in the replacement. The capture groups are concatenated together but the middle group has 1 subtracted from its value.

This will output to standard output so you can check that it does what you want. When you're happy, you can add the -i switch to overwrite the original file.

Upvotes: 3

mozzbozz
mozzbozz

Reputation: 3143

Basically, the command I came up with, was the following:

sed -r 's/(.*)(table\[)([0-9]+)(,)(.*)/echo "\1\2$((\3-1))\4\5"/ge' inputfile.c > outputfile.c

Well, this does not look very intuitive on the first sight - and I was missing good explanations for nearly every example I found.

So I will try to give a detailed explanation on this:

sed

--> basic command

-r

--> most examples you find are using -e; however, the -r parameter (only works with GNU sed) enables extended regular expressions and brings support for the + in a regex. It basically means "one or more matches".

's/input/output/ge'

--> this is the basic replacement syntax. It basically means "replace 'input' by 'output'". The /g is a "global" flag, i.e. sed will replace all occurences and not only the first one. You can add an additional e to execute the result in the bash. This is what we want to do here to handle the calculation.

(.*)

--> this matches "everthing" from the last match to the next match

(table\[)

--> the \ is to escape the bracket. This part of the expression will match Strings like table[

([0-9]+)

--> this one matches numbers with at least one digit, however, it can also match higher numbers with more than only one digit.

(,)

--> this simply matches the comma ,

(.*)

--> and again: the rest of the line

And now the interesting part:

echo "\1\2$((\3-1))\4\5"
  • the echo is a bash command
  • the \n (you can use every value from \1 up to \9) is some kind of "variable" for the inputs: \1 will contain the first match, \2 the seconds match, ... --> this helps you to preserve parts of the input string
  • the $((1+1)) is a simple bash syntax to calculate the value of the term inside the double brackets (in the complete sed command above, the \3 will of course be automatically replaced by the 3rd match, i.e. the 1st part inside the brackets to access the table's cells)
  • please note that we use quotation marks around the echo content to also be able to process lines with characters like & which would otherwise not work

The already mentioned e of \ge at the end will trigger the execution of the result in the bash. E.g. the first two lines of the example source code in the question would produce the following bash statements:

echo "void myFunction ("
echo "    &((int) table[$((1-1)), 0]),"

which is being executed and results in the following output:

void myFunction (
    &((int) table[0, 0]),

...which is exatcly what I wanted :)

BTW: text > output.c is simple bash syntax to output text (or in this case the sed-processed source code) to a file called output.c.


Good links about this topic are:

Ahh and one more thing: You can also use sed in the git-Bash on Windows - if you are "forced" to use Windows at work like me ;)

PS: In the meantime I could have easily done this by hand but using sed was a lot more fun ;)

Upvotes: 6

Related Questions