How do I decrement all array indexes in a text file?

Viewed 101

Background

I have a text file that looks like the following:

$SomeText.element_[1]="MoreText[3]";\r"
$SomeText.element_[2]="MoreText[6]";\r"
$SomeText.element_[3]="MoreText[2]";\r"
$SomeText.element_[4]="MoreText[1]";\r"
$SomeText.element_[5]="MoreText[5]";\r"

This goes on for over a thousand lines. I want to do the following:

$SomeText.element_[0]="MoreText[3]";\r"
$SomeText.element_[1]="MoreText[6]";\r"
$SomeText.element_[2]="MoreText[2]";\r"
$SomeText.element_[3]="MoreText[1]";\r"
$SomeText.element_[4]="MoreText[5]";\r"

Each line of text in the file should have the left most index reduced by one, with the rest of the text unchanged.

Attempted Solutions

So far I have tried the following...but the issue for me is I do not know how to feed it back into the file properly:

Attempt 1

I tried a double cutting technique:

cat file.txt | cut -d '[' -f2 | cut -d ']' -f1 | xargs -I {} expr {} + 1

This properly outputs all of the indicies reduced by one to the command line.

Attempt 2

I tried using awk with a mix of sed, but this caused by machine to hang:

awk -F'[' '{printf("%d\n", $2-1)}' file.txt | xargs -I {} sed -i 's/\[\d+\]/{}/g' file.txt

Question

How to I properly decrement all of the array indexes in the file by one and properly write the decremented indexes into the right location of the text file?

3 Answers

A Perl one-liner makes this easy, overwriting the input file:

perl -pi -e 's/(\d+)/$1-1/e' your-file-name-here

(assuming the first number on each line is the index)

With simple awk you could try following, written and tested with shown samples.

awk '
match($0,/\[[^]]*/){
  print substr($0,1,RSTART) count++ substr($0,RSTART+RLENGTH)
}
' Input_file

OR in case your Input_file's count in between [..] is in any order then simply reduce 1 from them as follows.

awk '
match($0,/\[[^]]*/){
  print substr($0,1,RSTART) substr($0,RSTART+1,RLENGTH)-1 substr($0,RSTART+RLENGTH)
}
' Input_file

With GNU sed and bash:

sed -E "s/([^[]*\[)([0-9]+)(].*)/printf '%s%d%s\n' '\1' \$((\2 - 1)) '\3'/e" file

Or, if it is possible that the lines contain ' character:

sed -E "
/\[[0-9]+]/{
    s/'/'\\\''/g
    s/([^[]*\[)([0-9]+)(].*)/printf '%s%d%s\n' '\1' \$((\2 - 1)) '\3'/e
}" file
Related