Search for a string at a particular position and replace with blank based on position

Hi,

I have a file with multiple lines(fixed width dat file). I want to search for '02' in the positions 45-46 and if available, in that lines, I need to replace value in position 359 with blank. As I am new to unix, I am not able to figure out how to do this. Can you please help me to achieve this?

Any attempts from your side? Which OS and shell are you using?

I tried with sed but it didnt work. Am using korn shell.

What sed command did you try?

Do you have Perl?
Try:

perl -ple 'substr $_, 358, 1," " if (substr $_, 44, 2) == "02";' Pradhikshan.file

I am assuming when you mention positions you're starting counting at 1, which is 0 for Perl.

perl -ple : # invoke the perl command at the command line with automatic printing of each line
substr $_, 358, 1," " : # replace the 359th character with blank (starts counting at 0) [if ...]
if (substr $_, 44, 2) == "02" : # ... if characters 45th and 46th make the string 02; (starting at 45th position take 2 characters).

I tried the below sed command.

sed '/(^.\{44\}\)02/s/\(^.\{358\}\).\{1\}\(.*\)/\1 \2/'

but didnt work out.

Would that do it?

sed 's/\(^.\{44\}02.\{312\}\).\(.*$\)/\1 \2/' 

It is always a good idea to tell us what operating system and shell you're using when asking questions here. With a standards conforming version of sed , you weren't far off with your sed command:

sed '/(^.\{44\}\)02/s/\(^.\{358\}\).\{1\}\(.*\)/\1 \2/'

When I try running that on Mac OS X (which has a BSD version of sed ), I get the diagnostic message:

sed: 1: "/(^.\{44\}\)02/s/\(^.\{ ...": RE error: parentheses not balanced

which can be fixed by adding a backslash before the 1st open parenthesis:

sed '/\(^.\{44\}\)02/s/\(^.\{358\}\).\{1\}\(.*\)/\1 \2/'

but I then get the diagnostic:

sed: 1: "/\(^.\{44\}\)02/s/\(^.\ ...": RE error: invalid repetition count(s)

The standards only require implementations of BRE parsing code to accept repetition counts up to 255, (and the 358 repetition count in the BRE in the substitute command exceeds that). If we change that to two repetition counts (each less than or equal to 255), it works:

sed '/\(^.\{44\}\)02/s/\(^.\{200\}.\{158\}\).\{1\}\(.*\)/\1 \2/'

but it can be simplified a little bit to just:

sed '/^.\{44\}02/s/^\(.\{200\}.\{158\}\)./\1 /'

If you want to try this on a Linux system (or another system using the GNU implementation of sed ), you might need something like:

sed --posix '/^.\{44\}02/s/^\(.\{200\}.\{158\}\)./\1 /'

but the GNU version might be able to handle the higher repetition count (I don't have a GNU sed to test at this point).

1 Like

Hi Don,

Thank you so much. It worked.

I tried the below command using awk which also worked.

awk '{if(substr($0,45,2)=="02") printf (substr($0,1,358) " " substr($0,360,length($0)) "\n");else printf ($0 "\n");}' file1 > file2

Regards,
Pradhikshan

Note that using:

printf (substr($0,1,358) " " substr($0,360,length($0)) "\n")

and:

printf ($0 "\n")

is very dangerous and can produce diagnostic messages or mangled output, and maybe also terminate your awk script instead of producing the output you want if there are any <percent-sign> or <backslash> characters in the input file you are processing. For your own safety, please change the above printf statements in your awk script to something more like:

printf("%s", substr($0,1,358) " " substr($0,360) "\n")
    or
printf("%s %s\n", substr($0,1,358),  substr($0,360))

and:

printf("%s", $0 "\n")
    or
printf("%s\n", $0)
    or much more simply
print $0
    or even just
print

respectively.