LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Newbie (https://www.linuxquestions.org/questions/linux-newbie-8/)
-   -   Replacing a particular position in a file (https://www.linuxquestions.org/questions/linux-newbie-8/replacing-a-particular-position-in-a-file-334543/)

sgracelin 06-17-2005 08:27 AM

Replacing a particular position in a file
 
Hi,

I have a file content as follows. The file content has got 5 columns each separated by ':' as field separator. I want to replace the value in the second column. ie if a value in second column is 333331 I have to replace with 777771. But if 333331 is in first or someother column other than 2nd column then it should not be replaced. Anyway to do this in Sed or AWK??

The file content as follows:
"33333110000":"333331238283":NULL:0:3
"33333110000":"444441001362":NULL:1:2
"9880222221":"333331708559":NULL:0:3
"9880222221":"333331001362":NULL:1:2
"9880222221":"444441001362":NULL:2:2
"9880222222":"333331414216":NULL:0:3
"9880222223":"333331858924":NULL:0:3
"9880222223":"333331001362":NULL:1:2
"9880222224":"333331803679":NULL:0:3
"9880222224":"333331001362":NULL:2:2
"9880333331":"333331733603":NULL:0:3
"9880333331":"444441001362":NULL:3:2


333331 in the second column should be replaced but 333331 in first column should not be replaced.

Thanks!!

zulfilee 06-17-2005 08:56 AM

Ok one way of doing it will be
I`ve replaceed 333331 with OOO


cat filename | sed "s/^\([^:]*:[^:]*\)333331\([^:]*:\)/\1OOO\2/"

But the above regex is too long
I`m trying for a better one

Cheers
Z

hpladd 06-17-2005 12:35 PM

Hey Z,

I'm studying linux and am having trouble understanding the sed command you detailed. It works. I tried it, but I don't understand it.

Here's my comprehension of the command (skipping over the cat portion):

1. s initiates a substitute operation.
2. ^ starts the search a beginning of the lines/strings
3. /(/) sequence places column A : column B into a buffer.
4. The first argument of the substitute operation is provided "33331"
5. Then /(/) places the first column of characters into a buffer. (again?)
6. The second argument of the substitute command is provided "\1000\2\/" This portion seems to say, recall buffer #1 and replace 33331 of the buffered data with 000, and then it recalls buffer 2.

I know I've taken a wrong turn in my thinking here. Would you be kind enough to point me to where I skipped track?

Also I would think that the command would need to end with /g.

Thanks

jonaskoelker 06-17-2005 04:23 PM

Token by token:
sed -- you got that right :)
s/ -- substitute the following with FOO
^ -- beginning of line
\( -- begin group (which you call buffer)
[^:]* -- match any number of any char that's not a colon; `*' means any number of (what preceeds it); [^abcd] means "anything except abcd" (in this case it's just `:').
: -- then match a colon
[^:]* -- then match any no. of not-colon again
\) -- end group 1
333331 -- the text you want to be replaced with (some other text).
\([^:]*:\) -- should be more or less obvious
/ -- # FOO begins here
\1 -- the contents of group 1 (i.e. everything up until 333331)
OOO -- the replacement text.
\2 -- the rest of the line.
/ -- # FOO ends here

Quote:

Also I would think that the command would need to end with `g'.
No--`g' means `global'. That is, replace *all* occurences of the pattern, not just the first. But since you only want to replace one pattern (the first), you don't need the g here.

I think this is more elegant, more correct and possibly faster too:
Code:

$ sed -r 's/^([^:]*:)333331/\1777771/' filename
It might be that `\1777771' gets interpreted as group number 1777771; try `\1(777771)' instead.

If all else fails, RTM :D

hth --Jonas

sgracelin 06-20-2005 12:45 AM

zulfilee's answer worked ..

zulfilee 06-20-2005 03:41 AM

Ok here is a better one


awk 'BEGIN{FS=":";OFS=":"}
{gsub("333331","AAAA",$2); print $0}' filename

BEGIN -> Start of script
FS,OFS are input and output field seperators.
[By default awl takes space as field separator]

gsub is a function which has this format
gsub(Pattern,Replacement,StringPosition)
And print $0 will printout the output


awk -F ":" '{gsub("333331","AAAA",$2); print $0}' filename
will also work .
Here we specify the filed seperator outside

[But ideally sub should be used instead of gsub.
gsub is global substitution]

Cheers
Z

sgracelin 06-20-2005 05:50 AM

Hi Z and everyone,

My file content is

"4444412000 ":"444441001362":"Kodiak2Grp "
"9880222221 ":"333331001362":"TestGrp1 "
"3333312221 ":"333331333331":"TestGrp1 "

The file has three fields....I have to replace 333331 in the second column only...the script

If the first 6 characters match the string then only it should be replaced..[if the last 6 or the any combination of six characters in the second column matches other than first 6 characters, then it should not be replaced]..

zulfilee 06-20-2005 06:46 AM

sed 's/^\([^:]*:"\)333331\([^:]*:\)/\1AAAA\2/' filename

Ive just removed the [^:]* and put a explicit " to the previous sed command.Means look for the first 6 chars

In awk it`ll be a bit long


awk -F ":" '{if ($2 ~ /^"333331/)
{sub("333331","AAA",$2) ;print $0}
else {print $0}} ' filename

Here we check if second string [: separated ] is staring with 33331
Or we print the line as it is.


You can write it more shortly too
Cheers
Z

sgracelin 06-20-2005 07:19 AM

thanks..

zulfilee 06-20-2005 08:13 AM

sed "s/^\([^:]*:\"\)$oldtr\([^:]*:\)/\1$newstr\2/"

SIngle quotes will mask the variable and try to serach is as $oldstr and not 333331

Just go for double quotes but then you have to escape the doulbe quote inside search with a backslash i.e \"

Cheers
Z

sgracelin 06-23-2005 04:47 AM

How to replace the string '33331' which comes in the beginning of 7th column alone has to be replaced...other 333331 in other columns should be retained as such..


2:"333331333331333331":"333331333331333331":"333331":1:1:1:"333331333331":"333331333331333331":1:1
12:"333331333331333331":"222221222221222221":"222221":1:1:1:"222221222221":"222221222221222221":1:1
12:"222221222221222221":"333331333331333331":"222221":1:1:1:"222221222221":"222221222221222221":1:1
12:"222221222221222221":"222221222221222221":"222221":1:1:1:"333331333331":"222221222221222221":1:1
12:"222221222221222221":"222221222221222221":"222221":1:1:1:"222221222221":"333331333331333331":1:1
12:"222221222221222221":"222221222221222221":"222221":1:1:1:"222221222221":"222221222221222221":1:1
12:"333331222221222221":"333331333331222221":"222221":1:1:1:"333331333331":"222221222221222221":1:1
12:"333331222221222221":"333331333331222221":"222221":1:1:1:"222221222221":"333331333331222221":1:1

zulfilee 06-23-2005 05:45 AM

The same awk script can be used as such

awk -F ":" '{if ($8 ~ /^"333331/)
{sub("333331","AAA",$8) ;print $0}
else {print $0}} ' filename

The pattern was in the 8 th column

In sed
sed 's/^\(\([^:]*:\)\{7\}\)"333331\(..*\)/\1"AAAA\3/' filename

^\(\([^:]*:\)\{7\}\) -> Here we Look for a pattern that comes as something:something 7 times.
"333331 -> Then we search for the string in the 8th field
\(..*\) -> The rest of the line

\1 -> is the first \( \) enclosure
and \3 is the last.


But in sed it doesnt look that good.

Cheers
Z

sgracelin 06-23-2005 05:56 AM

If I used AWK then the field separator disappears for those rows where the values were replaced...why is it so??

Output comes like this...

12 "333331333331333331" "333331333331333331" "333331" 1 1 1 "AAA333331" "333331333331333331" 1 1
12:"333331333331333331":"222221222221222221":"222221":1:1:1:"222221222221":"222221222221222221":1:1
12:"222221222221222221":"333331333331333331":"222221":1:1:1:"222221222221":"222221222221222221":1:1
12 "222221222221222221" "222221222221222221" "222221" 1 1 1 "AAA333331" "222221222221222221" 1 1
12:"222221222221222221":"222221222221222221":"222221":1:1:1:"222221222221":"333331333331333331":1:1
12:"222221222221222221":"222221222221222221":"222221":1:1:1:"222221222221":"222221222221222221":1:1
12 "333331222221222221" "333331333331222221" "222221" 1 1 1 "AAA333331" "222221222221222221" 1 1
12:"333331222221222221":"333331333331222221":"222221":1:1:1:"233333122221":"333331333331222221":1:1

Command:

awk -F ":" '{if ($8 ~ /^"333331/)
> {sub("333331","AAA",$8) ;print $0}
> else {print $0}} '

Any ideas??

zulfilee 06-23-2005 06:26 AM

Oops sorry then try this

awk 'BEGIN {FS=":";OFS=":"}
{if ($8 ~ /^"333331/)
> {sub("333331","AAA",$8) ;print $0}
> else {print $0}' filename

What happenned was awk has default OFS[o/p file seperator ] as space
this has replaced your orginal fs ":"

Cheers
Z

sgracelin 06-23-2005 06:40 AM

Thanks for the info(OFS)...Gr88


All times are GMT -5. The time now is 11:32 AM.