5

I have a file "test" like this:

RewiteEngine On
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.7$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.8$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.9$  [NC]
RewriteCond   %{REMOTE_ADDR}   ^192\.168\.1\.5$  [NC]
</Directory>

I want to replace \.1\.7,\.1\.8 and \.1\.9 by \.1\.10 so it will be:

RewiteEngine On
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.10$  [NC]
RewriteCond   %{REMOTE_ADDR}   ^192\.168\.1\.5$  [NC]
</Directory>

it might be replacement of m "IPS" by n "IPS", How can I reach this?

4 Answers 4

4

A perl solution:

$ perl -ple 's/\\\.1\\\.(7|8|9)/\\.1\\.10/' file | uniq
RewiteEngine On
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.10$  [NC]
RewriteCond   %{REMOTE_ADDR}   ^192\.168\.1\.5$  [NC]
</Directory>

If you want edit inplace, you can try:

perl -i.bak -nle 'next if $count and /!\^/;s/\\\.1\\\.(7|8|9)/\\.1\\.10/ and $count++ if /!\^/;print' file
12
  • Thanks, but are there other ways without using perl
    – Nidal
    Commented Aug 4, 2014 at 14:00
  • @Networker All perl is doing here is regex substitution. You can use sed in the same way if you don't like perl (and if you don't, shame on you!)
    – Joseph R.
    Commented Aug 4, 2014 at 14:12
  • @JosephR., I like perl (I like all scripting language indeed) but I want to benefit from Gnouc in more than one way.
    – Nidal
    Commented Aug 4, 2014 at 17:06
  • 1
    A more readable (for certain definitions of "readable") version of the regex could be: s/\Q\.1\.\E\K(7|8|9)/10/
    – Joseph R.
    Commented Aug 4, 2014 at 19:35
  • 1
    @JosephR.: Nice one! Forgot about \Q, \E
    – cuonglm
    Commented Aug 4, 2014 at 19:41
2

I have managed to do this by deleting all the lines and reinserting them, but I want an optimal solution (because here is deleting the whole line then adding a new whole line) and I want to add white spaces to the added lines:

delete:

sed -i '/!^.*$/d' test2

insert back:

 sed -i '/RewiteEngine On/aRewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.10$  [NC]' test2

the output is:

  RewiteEngine On
RewriteCond   %{REMOTE_ADDR}   !^192.168.1.10$  [NC] # need whites spaces at the begining
  RewriteCond   %{REMOTE_ADDR}   ^192\.168\.1\.5$  [NC]
2
sed '/!/d;/\(\^[^5]*\)./{h;s//!\110/p;g;}' <<\DATA
RewiteEngine On
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.7$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.8$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.9$  [NC]
RewriteCond   %{REMOTE_ADDR}   ^192\.168\.1\.5$  [NC]
</Directory>
DATA

OUTPUT

RewiteEngine On
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.10$  [NC]
RewriteCond   %{REMOTE_ADDR}   ^192\.168\.1\.5$  [NC]
</Directory>

So this relies on the s/ubsti/tution/ matching the last address - which it will do. When an /address/ is empty like s// or // the previous address is implied. It deletes all of /!/ lines containing a bang, then it addresses on a line with a ^ and puts that into hold-space. Then it edits it, prints it, and overwrites it again with its original value still in hold space.

But if the match address could match the hold line and the edited lines, then you could just keep editing them. Maybe like this:

sed '/!/d;/\(\^[^$]*\.\)[0-9]*/{h;s//!\110/p;s//\111/p;s//\112/p;g;}' <<\DATA
RewiteEngine On
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.7$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.8$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.9$  [NC]
RewriteCond   %{REMOTE_ADDR}   ^192\.168\.1\.5$  [NC]
</Directory>
DATA

OUTPUT

RewiteEngine On
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.10$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.11$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.12$  [NC]
RewriteCond   %{REMOTE_ADDR}   ^192\.168\.1\.5$  [NC]
</Directory>

Honestly, though, anymore than that and you'd probably want to approach it a little differently. Maybe with printf?

ips() { printf 's//\\1%d/p;' $(seq "$@") ; echo 'g;}' ; }

sed '/!/d;/\(\^[^$]*\.\)[0-9]*/{h;s//!\110/p;'"$(ips 11 30)" <<\DATA
RewiteEngine On
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.7$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.8$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.9$  [NC]
RewriteCond   %{REMOTE_ADDR}   ^192\.168\.1\.5$  [NC]
</Directory>
DATA

OUTPUT

RewiteEngine On
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.10$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.11$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.12$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.13$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.14$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.15$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.16$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.17$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.18$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.19$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.20$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.21$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.22$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.23$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.24$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.25$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.26$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.27$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.28$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.29$  [NC]
RewriteCond   %{REMOTE_ADDR}   !^192\.168\.1\.30$  [NC]
RewriteCond   %{REMOTE_ADDR}   ^192\.168\.1\.5$  [NC]
</Directory>
5
  • good one what if we want to replace \.1\.7,\.1\.8 and \.1\.9 by \.1\.10 and \.1\.11
    – Nidal
    Commented Aug 4, 2014 at 19:26
  • @Networker - if you modify it just a little bit to make the addresss more generic - slightly - like /\(\^[^$]*\.\)[0-9]*/ <that, then you can just keep on printing out new lines like s//!\110/p;s//\111/p;g and so on.
    – mikeserv
    Commented Aug 4, 2014 at 19:32
  • can you update your answer with new updates :)
    – Nidal
    Commented Aug 4, 2014 at 19:38
  • @Networker - mission accomplished.
    – mikeserv
    Commented Aug 4, 2014 at 20:04
  • @mikesev, amazing answer and amazing explanation thanks :)
    – Nidal
    Commented Aug 4, 2014 at 20:07
2

A way with gawk:

awk '{gsub(/\.[7-9]\$/,"\.10$")}!a[$0]++' test
5
  • Thanks it worked, but can you explain how the command worked and how can I make the change inline (inside the file).
    – Nidal
    Commented Aug 4, 2014 at 17:09
  • If should be awk '{gsub(/\\\.[7-9]/, "\\.10")} !a[$0]++' file
    – Srini
    Commented Aug 6, 2014 at 8:57
  • @Srini no it shouldn't
    – user78605
    Commented Aug 6, 2014 at 9:42
  • your code will remove '.' and it will replace even if there is no '\' before the number... echo '!^192\.168\.1\.7$ !^192\.168\.1.7$' | awk '{gsub(/\.[7-9]\$/,"10$")}!a[$0]++' will give you !^192\.168\.1\10$ !^192\.168\.110$
    – Srini
    Commented Aug 7, 2014 at 3:31
  • It's not supposed to check for a \ before a number. It did leave a . out though so i've changed that
    – user78605
    Commented Aug 7, 2014 at 7:05

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .