Need help on find and replacement on specific line and position

I have a file with 100 lines. On 50 th line , from position 5 to rest of the data , I need to change the occurrence of A to B and Occurrence of M to N.

Input file :

Line1 
Line2
Line3
--
--
12345ABCDEFM   

---
--
Line 100

Output

Line1 
Line2
Line3
--
--
12345BBCDEFN   

---
--
Line 100
awk 'NR==50{gsub("A","B");gsub("M","N")}1' file

I may have A or M from 1 to 6 but it should remain

Input file :

Line1 
Line2
Line3
--
--
1A345ABCDEFM 

---
--
Line 100

Output

Line1 
Line2
Line3
--
--
1A345BBCDEFN 

---
--
Line 100
sed '50s/A/B/;50s/M/N/' myFile

---------- Post updated at 04:25 PM ---------- Previous update was at 04:23 PM ----------

Please provide a representative sample of input and the desired output using code tags

A to B or M to N conversion should happen from position 6 to rest of the data in the line

awk '
        NR == 50 {
                i = sprintf ( "%s", substr ( $0, 1, 5 ) )
                j = sprintf ( "%s", substr ( $0, 6 ) )
                gsub ( "A", "B", j )
                gsub ( "M", "N", j )
                $0 = i j
        }
        1
' file
1 Like

Thanks a lot .. let me try and get back to u

A all of the others have produced sed and awk versions...
This is a longhand manual version using builtins only on OSX 10.7.5, default bash terminal.
There is always a way.
In this snippet your string is placed roughly halfway...

Last login: Wed Jan 15 22:06:27 on ttys000
AMIGA:barrywalker~> # Create an array as a tester.
AMIGA:barrywalker~> text=($(printf "12345lkjasldkja\n12345lclhflkjaflkaf\n12345ABCDEFM\n12345sdlklkdlfksd\n12345PWOEPOWER"))
AMIGA:barrywalker~> # Do two sustitutions on the second subscript.
AMIGA:barrywalker~> text[2]="${text[2]/A/B}"
AMIGA:barrywalker~> text[2]="${text[2]/M/N}"
AMIGA:barrywalker~> # Create and build a file.
AMIGA:barrywalker~> > /tmp/text
AMIGA:barrywalker~> echo "${text[0]}" >> /tmp/text
AMIGA:barrywalker~> echo "${text[1]}" >> /tmp/text
AMIGA:barrywalker~> echo "${text[2]}" >> /tmp/text
AMIGA:barrywalker~> echo "${text[3]}" >> /tmp/text
AMIGA:barrywalker~> echo "${text[4]}" >> /tmp/text
AMIGA:barrywalker~> # Now prove the file is correct.
AMIGA:barrywalker~> cat < /tmp/text
12345lkjasldkja
12345lclhflkjaflkaf
12345BBCDEFN
12345sdlklkdlfksd
12345PWOEPOWER
AMIGA:barrywalker~> _
1 Like

This works fine except for two points:

  1. The original request was to only make changes to line 50 in the input file.
  2. The original request was to change all occurrences of A to B and M to N in that line except that no changes are to be made to the 1st five characters on that line.
2 Likes

it is working .. thanks a lot

---------- Post updated 01-16-14 at 03:11 PM ---------- Previous update was 01-15-14 at 06:24 PM ----------

Hello.

If my 18 th line is

NM1*IL*1*LYNCH*WILLIAM****MI*11111

awk '
        NR == 18 {
                i = sprintf ( "%s", substr ( $0, 1, 10 ) )
                j = sprintf ( "%s", substr ( $0, 11 ) )
		  gsub ( "A", "Z", j )
                gsub ( "B", "Y", j )
                gsub ( "C", "X", j )
                gsub ( "D", "W", j )
                gsub ( "E", "V", j )
                gsub ( "F", "U", j )
                gsub ( "G", "T", j )
gsub ( "H", "S", j )
gsub ( "I", "R", j )
gsub ( "J", "Q", j )
gsub ( "K", "P", j )
gsub ( "L", "O", j )
gsub ( "M", "N", j )
gsub ( "N", "M", j )
gsub ( "O", "L", j )
gsub ( "P", "K", j )
gsub ( "Q", "J", j )
gsub ( "R", "I", j )
gsub ( "S", "H", j )
gsub ( "T", "G", j )
gsub ( "U", "F", j )
gsub ( "V", "E", j )
gsub ( "W", "D", j )
gsub ( "X", "C", j )
gsub ( "Y", "B", j )
gsub ( "Z", "A", j )
gsub ( "a", "z", j )
gsub ( "b", "y", j )
gsub ( "c", "x", j )
gsub ( "d", "w", j )
gsub ( "e", "v", j )
gsub ( "f", "u", j )
gsub ( "g", "t", j )
gsub ( "h", "s", j )
gsub ( "i", "r", j )
gsub ( "j", "q", j )
gsub ( "k", "p", j )
gsub ( "l", "o", j )
gsub ( "m", "n", j )
gsub ( "n", "m", j )
gsub ( "o", "l", j )
gsub ( "p", "k", j )
gsub ( "q", "j", j )
gsub ( "r", "i", j )
gsub ( "s", "h", j )
gsub ( "t", "g", j )
gsub ( "u", "f", j )
gsub ( "v", "e", j )
gsub ( "w", "d", j )
gsub ( "x", "c", j )
gsub ( "y", "b", j )
gsub ( "z", "a", j )
gsub ( 0, 9, j )
gsub ( 1, 8, j )
gsub ( 2, 7, j )
gsub ( 3, 6, j )
gsub ( 4, 5, j )
gsub ( 5, 4, j )
gsub ( 6, 3, j )
gsub ( 7, 2, j )
gsub ( 8, 1, j )
gsub ( 9, 0, j )

                $0 = i j
        }
        1
 ' test_tdm.dat

the ouput is

input ) NM1*IL*1*AYNCH*WILLISM****US11111
output ) NM1*IL*1*ABMCH*DILLISM****US
11111

My expectation is that after 1* , from L to 11111 everything should be changed as per AWK above but but only few letters got translated. any help on this

Maybe you didn't realize that if you change all occurrences of A to Z and then change all occurrences of Z to A, everything that was an A or a Z in the original input will be an A in the output. The sequences of gsub() calls that you have translate Z through N to A through M, z through n to a through m, and 9 through 5 to 0 through 4, respectively. The letters A through M, a through m, and the digits 0 through 4 are effectively unchanged (by changing each of them twice).

1 Like

without sequences , can we put everything together , so that i will achieve what i want or any other suggestion

How about this:

awk '
    BEGIN{
      F="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
      T="ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcba9876543210"
      for(i=1;i<length(F);i++)N[substr(F,i,1)]=substr(T,i,1);
    }
    NR == 18 {
      out=x
      for(i=1;i<length;i++) {
         c=substr($0,i,1)
         out=out (i>10&&(c in N)?N[c]:c)
      }
      $0=out
    }
    1
' infile
1 Like

not quite sure what 'you want or any other suggestion' - Don's explanation seems to be clear to me explaining what you're getting.
If for example, you want to change A to Z, but if there was a 'change' you don't what to change the 'changed' Z back to A, then

if (!gsub ( "A", "Z", j))
   gsub("Z","A",j)

You probably could optimize the whole thing with multiple gsub-s, with the lookup arrays and a single gsub iterating over the arrays......

1 Like

Based on ur code

the output is

NM1*IL*1*LBMXSDROORZNNRI97914

Where the * ( stars) ? it should be unchanged .. alpha should be alpha and numbers should be numbers.

Yes found that Issue and corrected the posted code - please try again

1 Like

it works. thanks a lot !

---------- Post updated at 05:29 PM ---------- Previous update was at 04:29 PM ----------

sorry to bother you again. Do you have any restriction in your code on maximum length in file

My input

N3*PO BOX 4703

ouput is

N3*KL YLC 529

Note : in this im converting from 4 th position to rest of the line

awk  -v k3="$k3" '
    BEGIN{
      F="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
      T="ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcba9876543210"
      for(i=1;i<length(F);i++)N[substr(F,i,1)]=substr(T,i,1);
    }
    NR == k3 {
      out=x
      for(i=1;i<length;i++) {
         c=substr($0,i,1)
         out=out (i>3&&(c in N)?N[c]:c)
      }
      $0=out
    }
    1
' $file

Many versions of awk limit the length of a line to LINE_MAX bytes. The value of LINE_MAX on your system can be found using getconf LINE_MAX ). But it looks like there is an off by one error that is causing your problem here. Try changing:

      for(i=1;i<length;i++) {

to:

      for(i=1;i<=length;i++) {
1 Like

i think i got what i need for

but i noticed 9 remains same

Input )

NM1*IL*1*AYNCH*AILLIAM****AI*R02089540

outpu )

NM1*IL*1*ZBMXS*ZROORZN****ZR*I97919459

So there were two off by one errors. Also change:

      for(i=1;i<length(F);i++)N[substr(F,i,1)]=substr(T,i,1);

to:

      for(i=1;i<=length(F);i++)N[substr(F,i,1)]=substr(T,i,1);
1 Like