0

Currently I'm using AWK to find and replace a portion of a string after the first three occurrences of a pattern. The string is formatted like this: func(tempID="39849235",count='12');, and there are many of these strings in the file as shown below:

func(tempID="39849235",count='12');
func(tempID="39849235",count='12');
func(tempID="39849235",count='12');
func(tempID="39849235",count='12');
func(tempID="39849235",count='12');
func(tempID="39849235",count='12');

Using this link, I was able to find a method of using AWK to find and replace the first three instances of the string. I changed it to what I needed it to do, and a snippet of my script is below:

id=12349876
awk -v id="$id" 'BEGIN {matches=0}
     matches < 3 && /.*tempID.*/ { sub(/tempID=.[0-9]+./,"tempID=\""id"\""); matches++ }
     { print $0 }' filName.py >filName.py.changed

The goal of the above code is to match on any line containing tempID and replace the number that is assigned to tempID with a value held in a variable named $id. The find and replace works well, but now I want to replace instances 4-9 with a different number. I tried the following method, but it still only replaced the first 5 instances of tempID:

id2=39843237
awk -v id2="$id2" 'BEGIN {matches=4}
     matches < 9 && /.*tempID.*/ { sub(/tempID=.[0-9]+./,"tempID=\""id2"\""); matches++ }
     { print $0 }' filName.py >filName.py.changed

Is there another way to implement this so that that range of values is replaced? It doesn't have to be with AWK, it can be with sed or any other Linux utility. In addition, the solution doesn't necessarily have to end at a certain point and is allowed to replace all instances after the third line, but if there's a solution that can do this, that would be a plus.

  • 1
    Setting matches=4 doesn't do what's needed: you need to start with matches=0, as before, then check for its value being 3 or more, as well as less than 9. – AFH Dec 3 '18 at 23:31
  • Good catch on that bug @KamilMaciorowski, edited. – AndreasKralj Dec 3 '18 at 23:54
  • @AFH Gotcha, thanks. I think I understand where you're coming from. Are you suggesting I simply need to add matches > 3 && matches < 9 to my code? – AndreasKralj Dec 4 '18 at 0:15
  • Yes, but @KamilMaciorowski has covered all the issues in his answer. – AFH Dec 4 '18 at 14:11
0

Your matches=4 and matches < 9 mean "assume there were 4 matches already, act until there are 9 in total". That's why the first 5 instances are replaced. You need to start form 0 as before, then include the lower limit into the logic:

id2=39843237
awk -v id2="$id2" 'BEGIN {matches=0}
 matches >=3 && matches < 9 && /.*tempID.*/ { sub(/tempID=.[0-9]+./,"tempID=\""id2"\"") }
 /.*tempID.*/ { matches++ }
 { print $0 }' filName.py >filName.py.changed

Note you need to do the replacement according to the value of matches but you need to increase this value every time a match occurs. Your original code replaced text and increased the value in one block. When there was no replacement due to matches being too high, the value was not increased further, but it didn't matter anymore. Now you can't get away with this simple approach. When there is no replacement due to matches being too low, you still need to increase the value if there's a matching string found.

Hence the two {} blocks with separate conditions.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.