I have a file which contains a very long string of characters and I would like to replace a substring of it with Ns. Example:



I would like to replace a substring of it with all letters N with awk command and sed, all the characters from index 5 to 8, so the total length of letter N is 4.



I tried something like this:

awk '{ v=substr($0,5,4); sed -i "s/$v/N/g";print substr($0,1,4)""v""substr($0,9,12)}' test

however, this command seems to give this output:


And no substitution was made

I would like to have in the code the number of the index from where to start the substitution, (here, for example, is 5) and the length number of the substitution ( here 4), so I can just modify these numbers in case I want to start in another position and for a different length of substitutions because in reality, I have a string with thousands of letter and I want to replace hundreds of characters so substitution of pattern does not work in my case

  • 2
    Awk is not like shell: you can't just put a sed call in there. Jul 11, 2019 at 20:18

5 Answers 5


With GNU awk, you can do

gawk -v start=5 -v end=8 '{
    mid = substr($0, start, end-start+1)
    print substr($0, 1, start-1) gensub(/./, "N", "g", mid) substr($0, end+1)
}' file

Or with perl

perl -spe 'substr($_, $start-1, $end-$start+1) =~ s/./N/g' -- -start=5 -end=8 file

With both solutions, we pass the start and end values to the program with command line options. This makes it easy to alter the values from within a shell script. If you need to make the replacement character N dynamic as well, it should be pretty obvious how.


If you have GNU awk (gawk) you could set FIELDWIDTHS to split the line into fields based on character positions. This is particularly convenient for your case in gawk version >= 4.2, which supports a "wildcard" trailing fieldwidth. You can then replace characters in the second field using gsub:

echo ABCDABCDABCD | ./gawk -v i=5 -v n=4 '
  BEGIN {FIELDWIDTHS = sprintf("%d %d *", i-1, n)} 
  {gsub(/./,"N",$2)} 1
' OFS=""

In older versions of gawk, you can simulate the * by choosing a suitably large maximum size for the trailing field:

echo ABCDABCDABCD | gawk -v i=5 -v n=4 '
  BEGIN {FIELDWIDTHS = sprintf("%d %d 65536", i-1, n)} 
  {gsub(/./,"N",$2)} 1
' OFS=""


Processing Fixed-Width Data

Capturing Optional Trailing Data


You can just try with below command

 echo "ABCDABCDABCD"| sed "s/ABCD/NNNN/2"



Using sed

To replace characters 5 through 8 with N:

$ sed -E 's/(.{4}).{4}/\1NNNN/' test

How it works:

  • (.{4}) captures the first four characters in group 1.

  • .{4} matches the next four characters.

  • \1NNNN replaces the above with group 1 and four N.

Using GNU awk

$ gawk -F "" '{for (i=5; i<=8; i++) $i="N"} 1' OFS="" test

How it works:

  • -F "" tells awk to treat each character as a separate field.

  • for (i=5; i<=8; i++) $i="N" loops over each character from 5 through 8 and changes it to N.

  • 1 tells awk to print the line.


You can do this by employing the following methods as shown with either POSIX or GNU seds

With the sed editor:

$ L=5 R=8
$ sed -e '
' ./test


With Perl:

perl -lspe '
   my $c = $idxr - (pos()=$idxl-1);
' -- -idxl=5 -idxr=8 ./test


You must log in to answer this question.

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