Change only first line of the match

The below is the code which works correctly.But my requiremnt is to change only first line of the match i.e first match not whe file.

RAFTIP=rt950test.info53.com
RAFTPORT=21250
sed '5 c\
leprechaun.host.uri.list=raft' HostSocket.txt > tmp.properties
mv -f tmp.properties HostSocket.txt

LINE=`cat HostSocket.txt | grep ^leprechaun.host.uri.list=`
sed s!${LINE}!leprechaun.host.uri.list=raft://${RAFTIP}:${RAFTPORT}!g HostSocket.txt > tmp.properties
mv -f tmp.properties HostSocket.txt

file contians line like below
hostsocket.txt

leprechaun.2.uri.list=leprechaun2urilist
leprechaun.3.uri.list=leprechaun3urilist
leprechaun.4.uri.list=leprechaun4urilist
leprechaun.5.uri.list=leprechaun5urilist^
leprechaun.host.uri.list=raft://rt900test.info53.com:20025
leprechaun.1.uri.list=leprechaun1urilist
leprechaun.2.uri.list=leprechaun2urilist
leprechaun.8.uri.list=leprechaun8urilist
leprechaun.9.uri.list=leprechaun9urilist
leprechaun.host.uri.list=raft://11.1.120.154:20527,raft://10.1.182.2:21527
leprechaun.4.uri.list=leprechaun4urilist
leprechaun.5.uri.list=leprechaun5urilist
leprechaun.6.uri.list=leprechaun6urilist

OUTPUT SHUOLD BE AS FOLLOWS:

leprechaun.2.uri.list=leprechaun2urilist
leprechaun.3.uri.list=leprechaun3urilist
leprechaun.4.uri.list=leprechaun4urilist
leprechaun.5.uri.list=leprechaun5urilist
leprechaun.host.uri.list=raft://rt950test.info53.com:21250
leprechaun.1.uri.list=leprechaun1urilist
leprechaun.2.uri.list=leprechaun2urilist
leprechaun.3.uri.list=leprechaun3urilist
leprechaun.4.uri.list=leprechaun4urilist
leprechaun.5.uri.list=leprechaun5urilist
leprechaun.6.uri.list=leprechaun6urilist
leprechaun.7.uri.list=leprechaun7urilist
leprechaun.8.uri.list=leprechaun8urilist
leprechaun.9.uri.list=leprechaun9urilist
leprechaun.host.uri.list=raft://11.1.120.154:20527,raft://10.1.182.2:21527
leprechaun.4.uri.list=leprechaun4urilist
leprechaun.5.uri.list=leprechaun5urilist
leprechaun.6.uri.list=leprechaun6urilist

Please help me in this requiremnt.

Please replace your sed statement with the below

sed -r '1s!${LINE}!leprechaun.host.uri.list=raft://${RAFTIP}:${RAFTPORT}!g HostSocket.txt' > tmp.properties

the -r is extended regexp and the 1 before s is used to replace only the firt match.

Hope it works.

Cheers!!

I don't understand what you're trying to do. Your current script changes line 5 in your target file so that that line and possibly others will be matched by a grep. If more than one line is matched by the grep, the second sed seems to be a no-op.

If you know that line 5 is the line you want to change, why not just make the 1st sed set that line to the final result that you want on that line and skip the second set of changes to that file?

Or try removing the g from the sed statement

sed s!${LINE}!leprechaun.host.uri.list=raft://${RAFTIP}:${RAFTPORT}! HostSocket.txt > tmp.properties

Removing the g will keep the substitute command from making more than one change on a given line; it will not keep it from changing the 1st occurrence on multiple lines. With the given sample file, the g doesn't do anything.

1 Like

Like this ??? I am confused .. :slight_smile:

$ cat file
leprechaun.2.uri.list=leprechaun2urilist
leprechaun.3.uri.list=leprechaun3urilist
leprechaun.4.uri.list=leprechaun4urilist
leprechaun.5.uri.list=leprechaun5urilist^
leprechaun.host.uri.list=raft://rt900test.info53.com:20025
leprechaun.1.uri.list=leprechaun1urilist
leprechaun.2.uri.list=leprechaun2urilist
leprechaun.8.uri.list=leprechaun8urilist
leprechaun.9.uri.list=leprechaun9urilist
leprechaun.host.uri.list=raft://11.1.120.154:20527,raft://10.1.182.2:21527
leprechaun.4.uri.list=leprechaun4urilist
leprechaun.5.uri.list=leprechaun5urilist
leprechaun.6.uri.list=leprechaun6urilist
awk -F. '   NR!=1 && $2-p>1{ 
                             y=$0; x=$2
                             while(++p<x){gsub(/[0-9]/,p,y);print y}
                           }
                 $2~/[0-9]/{ 
                            p=$2
                           }
               !z && /host/{
                             gsub(/[://].*:/,"://"RAFTIP,$0)
                             gsub(/[:0-9]*$/,":"RAFTPORT,$0)
                             z  = 1
                           }1
        ' OFS=. RAFTIP="rt950test.info53.com" RAFTPORT="21250" file
leprechaun.2.uri.list=leprechaun2urilist
leprechaun.3.uri.list=leprechaun3urilist
leprechaun.4.uri.list=leprechaun4urilist
leprechaun.5.uri.list=leprechaun5urilist^
leprechaun.host.uri.list=raft://rt950test.info53.com:21250
leprechaun.1.uri.list=leprechaun1urilist
leprechaun.2.uri.list=leprechaun2urilist
leprechaun.3.uri.list=leprechaun3urilist
leprechaun.4.uri.list=leprechaun4urilist
leprechaun.5.uri.list=leprechaun5urilist
leprechaun.6.uri.list=leprechaun6urilist
leprechaun.7.uri.list=leprechaun7urilist
leprechaun.8.uri.list=leprechaun8urilist
leprechaun.9.uri.list=leprechaun9urilist
leprechaun.host.uri.list=raft://11.1.120.154:20527,raft://10.1.182.2:21527
leprechaun.4.uri.list=leprechaun4urilist
leprechaun.5.uri.list=leprechaun5urilist
leprechaun.6.uri.list=leprechaun6urilist

Oops! I'm sorry. I must have replied without thinking twice.

Hi All,

I am very sorry for my late reply.Still the it is changing the second line withe below code.

sed s!${LINE}!leprechaun.host.uri.list=raft://${RAFTIP}:${RAFTPORT}! HostSocket.txt > tmp.properties

When i use AWK command.I am getting the below error.

$ ./code.sh
awk: 0602-521 There is a regular expression error.
        [] imbalance
 The source line number is 9.
 The error context is
                         >>>  gsub(/[:// <<< ].*:/,"://"RAFTIP,$0)

The code should search for leprechaun.host.uri.list=raft:// and it should only replace this line of first occurance and not touching the second occurance in the file.And i don't know the search is in which line.

Please let me know if i am clear or not.

You are not at all clear!
In your original message in this thread you said you had a file named hostsocket.txt that contains:

leprechaun.2.uri.list=leprechaun2urilist
leprechaun.3.uri.list=leprechaun3urilist
leprechaun.4.uri.list=leprechaun4urilist
leprechaun.5.uri.list=leprechaun5urilist^
leprechaun.host.uri.list=raft://rt900test.info53.com:20025
leprechaun.1.uri.list=leprechaun1urilist
leprechaun.2.uri.list=leprechaun2urilist
leprechaun.8.uri.list=leprechaun8urilist
leprechaun.9.uri.list=leprechaun9urilist
leprechaun.host.uri.list=raft://11.1.120.154:20527,raft://10.1.182.2:21527
leprechaun.4.uri.list=leprechaun4urilist
leprechaun.5.uri.list=leprechaun5urilist
leprechaun.6.uri.list=leprechaun6urilist

and that after changing one line shown in blue above and below, it should look like:

leprechaun.2.uri.list=leprechaun2urilist
leprechaun.3.uri.list=leprechaun3urilist
leprechaun.4.uri.list=leprechaun4urilist
leprechaun.5.uri.list=leprechaun5urilist
leprechaun.host.uri.list=raft://rt950test.info53.com:21250
leprechaun.1.uri.list=leprechaun1urilist
leprechaun.2.uri.list=leprechaun2urilist
leprechaun.3.uri.list=leprechaun3urilist
leprechaun.4.uri.list=leprechaun4urilist
leprechaun.5.uri.list=leprechaun5urilist
leprechaun.6.uri.list=leprechaun6urilist
leprechaun.7.uri.list=leprechaun7urilist
leprechaun.8.uri.list=leprechaun8urilist
leprechaun.9.uri.list=leprechaun9urilist
leprechaun.host.uri.list=raft://11.1.120.154:20527,raft://10.1.182.2:21527
leprechaun.4.uri.list=leprechaun4urilist
leprechaun.5.uri.list=leprechaun5urilist
leprechaun.6.uri.list=leprechaun6urilist

But, in addition to the changes marked in blue, the stuff marked in red in the original file was removed and the stuff in red in the updated file was added.

There are lots of fairly simple ways to do what your English description says you want to do. Akshay provided an awk script that comes close to producing the output you showed in your sample from your sample input, if you change:

                             gsub(/[://].*:/,"://"RAFTIP,$0)
                             gsub(/[:0-9]*$/,":"RAFTPORT,$0)

in his script to:

                             sub("//.*", "//"RAFTIP":"RAFTPORT

except that it doesn't remove the trailing circumflex from the 4th line of the input file.

The following alternative awk script seems to transform your sample input into what you said your output should be:

awk -F'[.]' '
/[.^.]$/ {      # Get rid of trailing circumflex...
        $0=substr($0,1,length($0)-1)
}
/^leprechaun[.]host[.]uri[.]list=/ {
        if(found++ == 0) {
                # Change IP address and Port on 1st matching line...
                sub("//.*", "//" RAFTIP ":" RAFTPORT)
                # Set starting sequence number for following lines.
                seq = 1
        }
        print
        next
}
found == 1 && seq <= $2 {
        end = $2
        # Insert missing lines between values between 1st and 2nd matched lines.
        while(seq <= end) {
                gsub(/[0-9]+/, seq++)
                print
        }
        next
}
{       print
}' OFS=. RAFTIP="rt950test.info53.com" RAFTPORT="21250" hostsocket.txt

Due to the considerable discrepancies between your description of what this script should do and the sample input and output provided, Akshay's script and this script make LOTS of assumptions (although his script and my script make different assumptions) that might or might not be what you want.

If you want to try this on a Solaris/SunOS system, change awk to /usr/xpg4/bin/awk , /usr/xpg6/bin/awk , or nawk .

If you give us a clear description of what you're trying to do and sample input and output that match that description, you stand a much better chance of getting a solution to your problem that doesn't waste out time. (And please use CODE tags.)

Hi Don,

Thanks a lot for your quick reply.And also i know your precious time should not be wasted.This code is working only for the sample input which i given.But i have lot many files like this.So i am passing parameters to change the file.I am not good in awk.So usually use sed to pass the parameters of RAFTIP and RAFTPORT to change hostsocket.txt.If i use awk script for my orginal file.It's going to infinite loop.Please help me with the script with what ever the file it may be.

sed s!${LINE}!leprechaun.host.uri.list=raft://${RAFTIP}:${RAFTPORT}! HostSocket.txt > tmp.properties

The above code is working fine.But it is replacing in all the matches.

You have already found that sed is not well suited to replacing only one occurrence of a string in a file.

We have shown you how to use awk to make the 3 different sets of changes you showed between your sample input and your sample output. You still have not given us an English specification of all of the changes that should be made to the input to produce the output. So, we have to assume that your real input does not match the assumptions we have made about your actual input based on the sample input you showed us.

Trying to guess at an input file specification from a short sample always leaves us to make assumptions. If our awk script are going into infinite loops, your real input does not match the assumptions we had to make from your sample input.

If you give us:

  1. the OS and release of that OS that you're using,
  2. the shell you're using,
  3. a clear specification of your input file format,
  4. a clear specification of all of the transformations to be made to turn your input into your desired output, and
  5. sample input and output files that match the above specifications

we may be able to help you come up with a script to do it. If you insist on using sed (with or without grep) to make the types of transformations you've shown us, you're out of luck.

Thanks for your reply.I am felxible to anything if it is AWK or sed.

Please find the below details about the environment which i am using.
Os AIX and /usr/bin/ksh

If you need full log it's too big.If you need it i can provide you.The fomat which i sent it right format.No any other changes in the format.

search string:

leprechaun.host.uri.list=raft://rt920test.info53.com:22025^M

rt920test.info53.com and 22025 are variables which i am passing through command promt.so these values are not fixed and the log file is also not fixed.

Replace string:

leprechaun.host.uri.list=raft://rt900test.info53.com:21025^M

But the code which was provided is working for the sample input which i given.

Please let me know if you need any more details.

Is the source that is producing hostsocket.txt a windows system? You never said anything before about having <carriage-return><newline> as your line terminator (rather than the standard UNIX <newline> by itself) before. Your sample file didn't have any <carriage-return> characters in it.

Are you copying our suggested code onto your system using an editor that uses <carriage-return><newline> instead of <newline> as line terminators? If so, it is no wonder that none of our code is working for you on AIX.

Does your input file really contain <carriage-return> characters?
Do you really want <carriage-return> characters in the output?
Do you want the script to remove the trailing circumflex characters as shown in your first example?
Do you want the script to add lines as shown in your first example?
To identify the line to be changed, which of the following do we need to match at the start of a line:

leprechaun.host.uri.list=raft://rt920test.info53.com:22025<carriage-return>
leprechaun.host.uri.list=raft://rt920test.info53.com:22025
leprechaun.host.uri.list=raft://
leprechaun.host.uri.list=raft:
leprechaun.host.uri.list=raft
leprechaun.host.uri.list=
leprechaun.host.uri.list

(where <carriage-return> is a visual representation of the single-byte carriage return character)? If it is one of the first two above, am I correct in assuming that we should accept the match only if the match is to the entire input line? You seem to be supplying your script with only the replacement text rather than the details of the IP and Port that are being changed, and your grep was looking for the next to the last entry above; but you latest message seems to be saying we should look for one of the first two???

Hi Don,

I tested the code without <carriage-return> for the i/p file.but still it is going to infinite loop as below.

Does your input file really contain <carriage-return> characters?
Yes it contains each and every line of the inputfile.

Do you really want <carriage-return> characters in the output?
It can be removed or if it is there also not a problem

Do you want the script to remove the trailing circumflex characters as shown in your first example?
No need

Do you want the script to add lines as shown in your first example?
To identify the line to be changed, which of the following do we need to match at the start of a line:

leprechaun.host.uri.list=raft://

My original inputfile looks as below:

##########################################################^M
# Leprechaun Settings^M
##########################################################^M
^M
leprechaun.enabled=TRUE^M
^M
leprechaun.character.encoding=Cd037^M
leprechaun.reconnect.wait.time=5010^M
leprechaun.max.wait.time=10200^M
leprechaun.keep.alive=TRUE^M
leprechaun.version.number=2.1^M
leprechaun.header.encryption.enabled=false^M
leprechaun.pin.encryption.enabled=true^M
leprechaun.captureStatistics=TRUE^M
leprechaun.extended.debug=@leprechaunextendeddebug@^M
leprechaun.max.request.size=16000^M
^M
#----- (New Way) Leprechaun without MQ ---- START ------^M
#^M
# The Following settings are used when leprechaun.pool.enabled^M
#  is set to true & leprechaun.JMS.enabled is set to false^M
#^M
# Most Environments will want to use this because of it no longer^M
#  has a dependency on MQ Series.^M
#^M
leprechaun.pool.enabled=TRUE^M
#example: leprechaun.pool.enabled=true {leprechaun.JMS.enabled=false when leprechaun.pool.enabled=true}^M
leprechaun.host.uri.list=raft://rt900test.info53.com:20025^M
leprechaun.ol1.uri.list=@leprechaunol1urilist@^M
leprechaun.ol2.uri.list=@leprechaunol2urilist@^M
leprechaun.ol3.uri.list=@leprechaunol3urilist@^M
leprechaun.ol4.uri.list=@leprechaunol4urilist@^M
leprechaun.ol5.uri.list=@leprechaunol5urilist@^M
leprechaun.ol6.uri.list=@leprechaunol6urilist@^M
leprechaun.ol7.uri.list=@leprechaunol7urilist@^M
leprechaun.ol8.uri.list=@leprechaunol8urilist@^M
leprechaun.ol9.uri.list=@leprechaunol9urilist@^M
leprechaun.ol10.uri.list=@leprechaunol10urilist@^M
leprechaun.ol14.uri.list=@leprechaunol14urilist@^M
leprechaun.ol15.uri.list=@leprechaunol15urilist@^M
leprechaun.ol20.uri.list=@leprechaunol20urilist@^M
leprechaun.ol18.uri.list=@leprechaunol18urilist@^M
leprechaun.ol19.uri.list=@leprechaunol19urilist@^M
leprechaun.ol23.uri.list=@leprechaunol23urilist@^M
leprechaun.ol25.uri.list=@leprechaunol25urilist@^M
leprechaun.ol30.uri.list=@leprechaunol30urilist@^M
leprechaun.ol35.uri.list=@leprechaunol35urilist@^M
###############################################^M
# The following onlines are added for user credintials ^M
# and will be used by HI_Direct for different environments ^M
# uol represents onlines where user credentials are required^M
###############################################^M
leprechaun.uol1.uri.list=@leprechaunuol1urilist@^M
leprechaun.uol2.uri.list=@leprechaunuol2urilist@^M
leprechaun.uol3.uri.list=@leprechaunuol3urilist@^M
leprechaun.uol4.uri.list=@leprechaunuol4urilist@^M
leprechaun.uol5.uri.list=@leprechaunuol5urilist@^M
leprechaun.uol6.uri.list=@leprechaunuol6urilist@^M
leprechaun.uol7.uri.list=@leprechaunuol7urilist@^M
leprechaun.uol8.uri.list=@leprechaunuol8urilist@^M
leprechaun.uol9.uri.list=@leprechaunuol9urilist@^M
leprechaun.uol10.uri.list=@leprechaunuol10urilist@^M
leprechaun.uol14.uri.list=@leprechaunuol14urilist@^M
leprechaun.uol15.uri.list=@leprechaunuol15urilist@^M
leprechaun.uol18.uri.list=@leprechaunuol18urilist@^M
leprechaun.uol19.uri.list=@leprechaunuol19urilist@^M
leprechaun.uol20.uri.list=@leprechaunuol20urilist@^M
leprechaun.uol23.uri.list=@leprechaunuol23urilist@^M
leprechaun.uol25.uri.list=@leprechaunuol25urilist@^M
#example: leprechaun.host.uri.list=raft://10.1.120.154:20127,raft://10.1.122.2:21327^M

This seems to do what you want for any number of files you want to process:

#!/bin/ksh
IAm=${0##*/}
if [ $# -lt 3 ] || [ $(($# % 3)) -ne 0 ]
then    printf "Usage: %s file1 IP1 Port1 [filen IPn Portn]...\n" "$IAm" >&2
        exit 1
fi
while [ $# -gt 1 ]
do      printf "Processing file: %s, New IP: %s, New Port: %s\n" "$1" "$2" "$3"
        ed -s "$1" <<-EOF
                /^leprechaun[.]host[.]uri[.]list=raft:\/\//s,//[[:alnum:].:/]*,//$2:$3,
                w
                q
EOF
        shift 3
done

It will work whether or not you have carriage returns in your file (if they are in your input file, they will not be removed; if they are not in your input file, they will not be added).

The earlier scripts weren't working for several reasons, possibly including, but not necessarily limited to:

  1. Your sample file had two lines that match your pattern; your real file only has one.
  2. The second field in the lines after the 1st matched line had numeric strings between the 1st and 2nd periods on the line; your real file does not.
  3. Your sample input and output showed that you wanted us to add lines in increasing numeric order if numbers were missing in the sequence between the 1st and 2nd matches in your input file; your real input file has neither numeric strings nor two matching lines.

Hi Don,

Thanks your valauable code.

In my Sample text file i have same searching string but the full line is not same as the one which i am going to change.So if i use sed it will also change the below line:

#example: leprechaun.host.uri.list=raft://10.1.120.154:20127,raft://10.1.122.2:21327^M

Can you let us know how this code will work for my sample file.I am passing my inputs as shown in the below code and the output i am receving:

#!/bin/ksh
file1=HostSocket.properties
IP1=rt900test.info53.com
Port1=23054
IAm=${0##*/}
if [ $# -lt 3 ] || [ $(($# % 3)) -ne 0 ]
then    printf "Usage: %s $file1 $IP1 $Port1 [filen IPn Portn]...\n" "$IAm" >&2
        exit 1
fi
while [ $# -gt 1 ]
do      printf "Processing file1: %s, New IP1: %s, New Port1: %s\n" "$1" "$2" "$3"
        ed -s "$1" <<-EOF
                /^leprechaun[.]host[.]uri[.]list=raft:\/\//s,//[[:alnum:].:/]*,//$2:$3,
                w
                q
EOF
        shift 3
done

output:

Usage: test.sh HostSocket.properties rt900test.info53.com 23054 [filen IPn Portn]...

Maybe I got this thread confused with another thread. I thought you had lots of files that needed to be modified in similar ways but with different IP and Port values for different files. The idea of editing your script to make it work for each different file defeats the purpose of writing a script in the first place. Adding three variables to the start of my script and changing the usage message won't make it work. Try taking the script I gave you in message #15 in this thread and invoke it like this:

test.sh HostSocket.properties rt900test.info53.com 23054

and if you have two files to be changed, you could invoke it like this:

test.sh HostSocket.properties rt900test.info53.com 23054 2ndHostSocket.properties rt900test.info53.number2.com 22222

The script is set up to process sets of the arguments where the 1st argument in each set is the name of the file to be updated, the 2nd argument in each set is the new IP to be used for that file, and the 3rd argument in each set is the Port to be used for that file.

In an earlier post I asked:

and you replied:

leprechaun.host.uri.list=raft://

The script I gave you will not change the line:

#example: leprechaun.host.uri.list=raft://10.1.120.154:20127,raft://10.1.122.2:21327^M

because #example is at the start of the line; not leprechaun... . There is only one line in any of your sample input files where

leprechaun.host.uri.list=raft://

appears at the start of a line.

And, I repeat. If you have more than one line that matches a pattern, you want to change the 1st matching line, and keep all of the other lines unchanged; sed is not the tool you want to use for this project.

I am very sorry for my late response.Thanks Don for your support.It works fine now.