Sed command to globally replace xth occurance.

This should replace the 1st and the 3rd occurance of "the":

sed -e "s/ the / those /1;s/ the / these /3"

This works only by line.

If there is a second "the", but in an other line for example, it counts it as 1st again and replaces it again.

How can I replace "the" 1st and 3rd occurance globally with sed?

Use Perl:

perl -i.bck -0777 -pe'
  s/\bthe\b/++$c==3?those:$c==1?these:$&/ges
  ' infile

here's a more readable version

awk '{
 j=0
 for(i=1;i<=NF;i++){
   if ($i == "the"){        
        j++
        if (j==1) {
            $i = "those"
        }else if (j==3){
            $i = "these"
        }     
   }
 }
 print $0   
}
'  file

Bare in mind that assigning a value to a field will have side effects (FS to OFS).

yes i agree with radoulov on that

awk '/the/{n+=1}{if(n==1||n==3){sub("the","OK",$0)};print}' filename

this looks absolutely beautiful, and it would be nice to work with, but I end up in this error:

+ awk '{ j=0 for(xi=1;xi<=NF;xi++){ if ($xi == "the"){j++ if (j==1) { $xi = "those" }else if (j==3){ $xi = "these" }}}print $0}'
awk: syntax error at source line 1
context is
{ j=0 >>> for <<< (xi=1;xi<=NF;xi++){ if ($xi == "the"){j++ if (j==1) { $xi = "those" }else if (j==3){ $xi = "these" }}}print $0}
awk: illegal statement at source line 1

However, the perl solution works great...

but how can I add a variable similar like this perl/sed mix (which ofcourse does not work this way):

perl -pe' s/\bthe\b/++$c==3?those ${kw2} :$c==1?these ${kw1} :$&/ges '

Thanx a lot!

why do you want to cramp everything to one line? makes your code ugly to read. Indent your code properly. one liners are cool, but not that cool when you have to troubleshoot your problems.
if you absolutely want to cramp everything to one line, make sure you use appropriate ";".

awk '{ j=0 ; for (...... }' 

-----Post Update-----

i see a logic problem here. n cannot be both equal 1 AND 3 at the same time. therefore your substitution will not work. also i think OP wants to change the "the"s on a line. If there are multiple "the"s on a line, /the/ will only count as 1. Also, what about resetting back n to 0 ?

while i agree with both of you as well about changing the fields, however, in this simple case, its alright.

... I know I know. I need a quick solution for a problem and did not digg deeper into all those fantastic sed/awk/perl stuff...

you are absolutely right, oneliners are very very bad for reading.

You should see my code... nearly all pocessing is done in one line, a lynx output piped again and again... kilometers long.

And the more readable version of it made me even understand what this onliners really are...

Now this AWK solution of ghostdog74 works allmost perfect, if I put the ; to the right places, but

I need this to count the "the"s of all lines, this solution seems to count and replace only per line, like my simple sed example at the beginning...

Thanx alot! :slight_smile:

Sorry I did a typing mistake its not && it should be ||
thanks for pointing it out :slight_smile:

ah...so its not on each line, but one all lines .... my bad.

perl -i.bck -0777 -pe'BEGIN {
        ( $v1, $v2 ) = ( $ENV{kw1}, $ENV{kw2} );
    }
    s/\bthe\b/
        ++$c == 3 ?
      "those $v2 " :
        $c == 1    ? 
        "these $v1 " :
          $&
      /xges
  ' infile

Thanx for this, but my $v1, $v2 stays empty for some reason. What have I to do to to move the content of kw1 to v1?

part1=$(perl -e 'srand; rand($.) < 1 && ($line = $_) while <>; print $line;' /text/part1.TXT)
part2=$(perl -e 'srand; rand($.) < 1 && ($line = $_) while <>; print $line;' /text/part2.TXT)
part3=$(perl -e 'srand; rand($.) < 1 && ($line = $_) while <>; print $line;' /text/part3.TXT)
part4=$(perl -e 'srand; rand($.) < 1 && ($line = $_) while <>; print $line;' /text/part4.TXT)
part5=$(perl -e 'srand; rand($.) < 1 && ($line = $_) while <>; print $line;' /text/part5.TXT)
part6=$(perl -e 'srand; rand($.) < 1 && ($line = $_) while <>; print $line;' /text/part1.TXT)
part7=$(perl -e 'srand; rand($.) < 1 && ($line = $_) while <>; print $line;' /text/part1.TXT)
part9=$(perl -e 'srand; rand($.) < 1 && ($line = $_) while <>; print $line;' /text/part1.TXT)
part8=$(perl -e 'srand; rand($.) < 1 && ($line = $_) while <>; print $line;' /text/part4.TXT)
...
kw1=`echo "$kwt $part9 $kwt $part2 - $kwt - $part6 | $kwt $part8 - $kwt"`
...
...
perl -i.bck -0777 -pe'BEGIN {
        ( $v1, $v2 ) = ( $ENV{kw1}, $ENV{kw2} );
    }
    s/\bthe\b/
        ++$c == 3 ?
      "those $v2 " :
        $c == 1    ? 
        "these $v1 " :
          $&
      /xges
  ' infile

You need to export them:

kw1=...
kw2=...
export kw1 kw2

works like a charm!

Thanx!

Here is my sed one-liner for this problem:

sed -n '1h;1!H;${x;s/the/those/1;s/the/these/2;p}' input_file

Basically, what it does is to accumulate the whole file in the hold buffer ( 1h;1!H ) and then when sed reaches the end of the file ($) it copies the content of the hold buffer back to the pattern buffer where the replacements take place.

However, i would not recommend using this solution with large files, because it can be memory-consuming (the whole file will be buffered, instead of the usual one line)