Can sed replace every 2 instances it finds in a file? Pattern.

My goal is to make a script to find/replace the variable "PORT" with a unique number.

Like the following

<VirtualHost 174.120.36.236:PORT>
    ServerName architect.com.ph
    ServerAlias www.architect.com.ph
    DocumentRoot /home/architec/public_html
    ServerAdmin webmaster@architect.com.ph
    UseCanonicalName Off
    CustomLog /usr/local/apache/domlogs/architect.com.ph combined
    CustomLog /usr/local/apache/domlogs/architect.com.ph-bytes_log "%{%s}t %I .\n%{%s}t %O ."
    ## User architec # Needed for Cpanel::ApacheConf
    <IfModule mod_suphp.c>
        suPHP_UserGroup architec architec
    </IfModule>
    <IfModule !mod_disable_suexec.c>
        SuexecUserGroup architec architec
    </IfModule>
    ScriptAlias /cgi-bin/ /home/architec/public_html/cgi-bin/


    # To customize this VirtualHost use an include file at the following location
    # Include "/usr/local/apache/conf/userdata/std/2/architec/architect.com.ph/*.conf"

</VirtualHost>

        backend architect.com.ph {
                set backend.host = "architect.com.ph";
                set backend.port = "PORT";
        }

The problem is that inside this file there are hundreds of virtualhosts, and other config files.

I am wondering if sed can go through a pattern of every 2 instances it finds of "PORT" to be replaced with a unique number, or better yet sequential, is this possible?

Thanks

Do you mean you want to ignore the port in: -

<VirtualHost 174.120.36.236:PORT>

and just change the one in quotes: -

set backend.port = "PORT";

If so couldn't you just change the PORT on lines containing backend.port?

No, I want to replace both of them.

That is why I wanted it in a pattern, for every 2 instances it finds the word "PORT" to replace it with a unique number, and every 2 instances it finds to replace it with a unique number, and so forth.

Thanks

Something like:

sed 's/PORT/99999/g' file

That is going to replace all instances, i dont want that. i want it to replace every two instances it finds of PORT . That is my dilema right now.

Thanks

---------- Post updated at 02:28 PM ---------- Previous update was at 02:28 PM ----------

That is going to replace all instances, i dont want that. i want it to replace every two instances it finds of PORT . That is my dilema right now.

Thanks

Which 2 instances? The first 2 instances, the second 2...?

Pretend this file has thousands of instances that say PORT

I want it to replace every two instances it finds that say PORT with a unique number. None are the same so incremental is fine. But every time it find two instances of PORT to replace those two, then move on to the next two, and so forth.

Is such possible?

---------- Post updated at 02:36 PM ---------- Previous update was at 02:36 PM ----------

Pretend this file has thousands of instances that say PORT

I want it to replace every two instances it finds that say PORT with a unique number. None are the same so incremental is fine. But every time it find two instances of PORT to replace those two, then move on to the next two, and so forth.

Is such possible?

Sure:

awk '/PORT/ && gsub("PORT",int(i)){i+=0.5}1' file

Sweet, you sir, are a god...

Can you tell me what does this do?

"int(i)){i+=0.5}1"

What can I change if I want it to do every 3 instances or maybe start like at 4000 for the integer?

I believe you want to replace each pair of mentions of PORT with a unique port number, the following does that:
Test file before running script:

$ cat port_test
1:PORT
2:PORT
3:PORT
4:PORT
5:PORT
6:PORT
7:PORT
8:PORT
9:PORT
11:PORT
12:PORT
13:PORT
14:PORT
15:PORT
16:PORT
17:PORT
18:PORT
19:PORT
21:PORT
22:PORT
23:PORT
24:PORT
$ 

Test file after running script:

$ cat port_test
1:1000
2:1000
3:1001
4:1001
5:1002
6:1002
7:1003
8:1003
9:1004
11:1004
12:1005
13:1005
14:1006
15:1006
16:1007
17:1007
18:1008
19:1008
21:1009
22:1009
23:1010
24:1010
$ 

Script to do the above:

$ cat port_test.sh
index=1000
STARTLINE=1
ENDLINE=`expr ${STARTLINE} + 1`
while [ ${index} -lt 1500 ]; do
  sed -e ''${STARTLINE}','${ENDLINE}'{
s/PORT/'${index}'/ 
}' port_test > port_test.$$ && \
  cp port_test.$$ port_test
  index=`expr ${index} + 1`
  STARTLINE=`expr ${STARTLINE} + 2`
  ENDLINE=`expr ${STARTLINE} + 1`
done
rm port_test.$$
$

This should work in Bourne and BASH shells.
Increase the value 1500 to reflect the number of lines to be changed in your file, in my example's case it could have been set to 1011.

HTH.

Explanation:

gsub("PORT",int(i))

substitute all instance of PORT in the current line with the integer of i

{i+=0.5}1

increase i with 0.5 and print the line

This approach suites for 2 instances:

If you don't have to much substitutes, you can try some thing like for 3 instances if you want to start with 4000:

awk -v i="4000" '/PORT/ && gsub("PORT",int(i)){i+=0.33334}1' file

Nicely done, Franklin52.

I took the liberty of building on your solution and parameterizing it. i=starting port number, n=how many times to reuse a port number:

awk '/PORT/ && gsub("PORT",i){i+=!(++j%n)}1' i=1 n=2 file

Regards,
Alister

Thanks Alister, this did the trick perfectly.

Thank you, I can't thank you enough.

I had something similar to that in mind with a mod operator but with NR:

awk '/PORT/ && gsub("PORT",i){i+=!(NR%n)}1' i=4000 n=3 file

Regards

NR won't work in this case, though. NR will increment for every line regardless of whether a PORT substituion occured. The "substitution" counter needs to be something independent of NR (j in my version).

On an unrelated note, since gsub returns the number of substitutions made, we can further reduce the code to:

awk 'gsub(/PORT/,i){i+=!(++j%n)}1' i=1 n=2 file

Like the earlier versions of this approach, it treats multiple substitutions on a single line as one. That's probably a bug. Though if we can be certain that only one instance of PORT will occur on a line, then it's fine, and as a bonus we can reduce by one more character:

awk 'sub(/PORT/,i){i+=!(++j%n)}1' i=1 n=2 file

And that concludes this episode of OCD AWKing. Thank you for tuning in. :wink:

Cheers,
Alister

Oh my bad you're right, I was using the example file of post #10 of TonyFullerMalv :eek:

Very nice:b:!

The following correctly handles multiple instances of "PORT" on a single line:

awk '{while (sub(/PORT/,i)) i+=!(++j%n)}1' i=1 n=1 data

Finally, we can put this one to bed. :slight_smile:
Alister