0

I have a file with multiple lines (no. of lines unknown)

DD0TRANSID000019021210504250003379433005533665506656000008587201902070168304000.0AK  0000L00000.00  N          01683016832019021220190212N0000.001683065570067.000000.00000.0000000000000NAcknowledgment                                                                                                                                        
DD0TRANSID000019021210505110003379433005535567606656000008587201902085381804000.0FC  0000L00000.00  N          53818538182019021220190212N0000.053818065570067.000000.00000.0000000000000NFirst Contact                                                                                                                                         
DD0TRANSID000019021210510360003379433005535568006656000008587201902085381804000.0SR  0000L00000.00  N          53818538182019021220190212N0000.0

The text TRANSID000 is in every line starting from 3rd to 10th poisition I need to be able to replace it with TRAN000066 in increments of 1

66 is a variable I am getting from another file (say nextcounter) for storing the start of the counter. Once the program updates all the lines, I should be able to capture the last number and update the nextcounter file with it.

Output

DD0TRAN00066019021210504250003379433005533665506656000008587201902070168304000.0AK  0000L00000.00  N          01683016832019021220190212N0000.001683065570067.000000.00000.0000000000000NAcknowledgment                                                                                                                                        
    DD0TRAN00067019021210505110003379433005535567606656000008587201902085381804000.0FC  0000L00000.00  N          53818538182019021220190212N0000.053818065570067.000000.00000.0000000000000NFirst Contact                                                                                                                                         
    DD0TRAN00068019021210510360003379433005535568006656000008587201902085381804000.0SR  0000L00000.00  N          53818538182019021220190212N0000.053818065570067.000000.00000.0000000000000NStatus Report                                                                                                                                         
1

With perl:

perl -spe 's/TRANSID000\K/$n++/e' -- -n=66 < your-file

Or if you need the number to be padded with 0s to a length of 5 (00001, 00010, 00100...):

perl -spe 's/TRANSID\K000/sprintf "%05d", $n++/e' -- -n=66 < your-file
  • Thank you. Is it possible to have n as variable ? I tried perl -spe 's/TRANSID\K000/sprintf "%05d", $n++/e' -- -n=$variable < your-file and it did not work. I am not very familiar with perl syntax. – Rohit Prasad Apr 8 at 7:45
  • @RohitPrasad, in which way did it not work? Note that in bash and all Bourne-like shells but zsh, parameter expansions need to be quoted: -n="$variable" (or "-n=$variable", etc). Is it possible that you variable contain whitespace? Possibly CR character? Check printf %s "$variable" | od -tc -tx1 – Stéphane Chazelas Apr 8 at 8:39
  • Thank you it worked. Much appreciated. – Rohit Prasad Apr 8 at 13:52
1

I think this awk script should do the job. It does everything from within the script as this the simplest setup. But see further on for an alternative that lets you handle your nextcounter as a shell variable:

BEGIN
    { getline counter < "nextcounter"; }
/TRANSID000/
    {
      replacement_string = sprintf("TRAN%05d", counter++);
      gsub("TRANSID000", replacement_string);
      print;
    }
END
    { printf("%d\n", counter) > "nextcounter"; }

You may invoke it with a one-liner like this:

cat data | awk -- 'BEGIN { getline counter < "nextcounter"; } /TRANSID000/{ replacement_string = sprintf("TRAN%05d", counter++); gsub("TRANSID000", replacement_string); print; } END { printf("%d\n", counter) > "nextcounter"; }'

Please note:

  • In your OP you first say that you want a string like TRAN000066 i.e. having 6 digits in all, but then your sample output has a string like TRAN00066 i.e. with 5 digits. I followed your sample output but if instead you need 6-digits precision just change the TRAN%05d string with TRAN%06d
  • As per your description I considered the number taken from the nextcounter file as being the first number to use in replacement. If instead you want to first increment the number just change the counter++ piece with ++counter
  • I considered nextcounter as a file containing only one line with only a numeric integer number. If that's not precisely the case then you'll need to modify the script's BEGIN and END section

If you prefer not to have the awk script update your nextcounter file directly, and instead handle such nextcounter value as a shell variable, you need a bit more complicated setup which involves using a temporary file to store the updated counter. Something like this:

tempfile=$(mktemp) ; cat data | awk -v counter="${nextcounter:-0}" -v tempfile="${tempfile}" -- '/TRANSID000/{ replacement_string = sprintf("TRAN%05d", ++counter); gsub("TRANSID000", replacement_string) ; print; } END { printf("%d\n", counter) > tempfile; }' && read nextcounter < "${tempfile}" ; rm "${tempfile}"

Broken down for explanation:

tempfile=$(mktemp) \ # create temporary file
cat data | pipe data to awk ...
    awk -v counter="${nextcounter:-0}" -v tempfile="${tempfile}" -- \ # provide initial counter and tempfile to awk
    '/TRANSID000/ \
        { replacement_string = sprintf("TRAN%05d", ++counter); \
          gsub("TRANSID000", replacement_string) ; \
          print; \
        } \
     END \
        { printf("%d\n", counter) > tempfile; }' \ # write updated counter to temporary file
    && read nextcounter < "${tempfile}" \ # read updated counter into ${nextcounter} shell variable
rm "${tempfile}"

This expects the initial counter in ${nextcounter}, and updates that same variable at the end.

IF creating temporary files is not an option, then you might try using file-descriptors over unnamed pipes, but this requires Bash v3+ and a system that allows opening pipes in read/write mode. Linux allows that, MacOS doesn’t, don’t know about other Unix-es.

It would be like:

exec 9<> <(:) ; cat data | awk -v counter="${nextcounter:-0}" -- '/TRANSID000/{ replacement_string = sprintf("TRAN%05d", ++counter); gsub("TRANSID000", replacement_string); print; } END { printf("%d\n", counter) > "/dev/fd/9"; }' && read nextcounter <&9 ; exec 9<&-

Broken down:

exec 9<> <(:) # open fd 9 onto unnamed pipe R/W
cat data | \
    awk -v counter="${nextcounter:-0}" -- \
    '/TRANSID000/ \
         { replacement_string = sprintf("TRAN%05d", ++counter); \
           gsub("TRANSID000", replacement_string); \
           print; } \
      END \
         { printf("%d\n", counter) > "/dev/fd/9"; }' \ # write updated counter to fd 9
    && read nextcounter <&9 # read updated counter from fd 9 into ${nextcounter} shell variable
exec 9<&- # close fd 9
0

if your file in 'file', on bash shell type,

inp=66;i=$inp; while read -r ln;do;echo $ln sed -E "s/TRANSID000/TRAN0000$i/i";let i++;done<file
  • 1
    Would you be able to explain the command a bit? It seem like $i is a positive integer, but since it's not zero-filled to a fixed width, the result may be unexpected. – Kusalananda Apr 8 at 6:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.