Link to home
Start Free TrialLog in
Avatar of ITD_Technician
ITD_Technician

asked on

Adding/Replacing lines with SED

Having trouble with getting SED to do what I want it to. The Win32 port seems to work a little differently then the linux version.

Here is the sample data:

[Registration]
User=Administrator
Number=HJ-4493MNB
NextID=67145
Check=Y

[Locations]
IconDirectory=c:\working
SoftwareDirectory=e:\build
Help=c:\working\work.hlp
RemoteConnection=RemoteDatabase
LocalLibrary=C:\working\local_library.pbl


[LocalDatabase]
DBMS=ODBC
Database=generic_data
UserID=Admin
UsePassword=Y
Check=Y


I need to change the first instance of "CHECK=Y" to "CHECK=N" and then add a line underneath that adds "IDText=Y".

This swaps the text properly, but it does it for all instances in a file, not just the first one.
sed "s/Check=Y/Check=N/" danic.ini > danic2.ini

And I can't seem to figure out the proper command to add a line after it finds the first instance of a string.

Any help would be appreciated.
Avatar of KirillMueller
KirillMueller

This is a nice collection of short sed programs:

sed.sourceforge.net/sed1line.txt

The following examples are from there:

sed 's/foo/bar/'             # replaces only 1st instance in a line
sed 's/foo/bar/4'            # replaces only 4th instance in a line
sed 's/foo/bar/g'            # replaces ALL instances in a line

Perhaps your Win32 port has the 'g' option set automatically. Try

's/foo/bar/1'.

If you need to insert a new line after the replaced line, add

'\n<contents of new line>'

to the replace string, that should do the job.
Sorry, I was wrong about my first suggestion, this was about finding instances _in a line_.

The following sed program will do the job, I've tested it:

sed '{:start {s/^foo.*$/bar\nbaz/;t end;n;T start}};{:end n; b end}'

Synopsis: The first line that begins with foo is replaces with two lines that contain bar and baz, the rest of the file remains untouched.

The t and T commands are for flow control. The first block executes the search command and jumps to the second block upon success. The second block simply prints the input as is.

I'm curious whether there are more elegant solutions to this.
Avatar of ITD_Technician

ASKER

Unfortunately I don't think the linux version and the windows version see eye to eye.

This is what I tried:
sed "{:start {s/^Check=Y.*$/Check=N\nIDText=Y/;t end;n;T start}};{:end n; b end}" danic.ini > danic2.ini

Gives this error:
sed: -e expression #1, char 51: Unknown command: ``T''

I am using 3.02 if it helps
I built the script with version 4.1.x. Could you try to replace T with b, or use a newer build of sed?
It works with the newer one except it removed all the return characters. Output looks like this:

[Registration]User=AdministratorNumber=HJ-4493MNBNextID=67145Check=NIDText=Y[Locations]IconDirectory=c:\working.....
What kind of line endings does your source file use? Is it CR/LF or something else?

Anyway, try the current version of sed from

http://gnuwin32.sourceforge.net/packages/sed.htm
Yeah the newest version is what wraps everything to the same line.
Could you post your input file to this forum, please?

Did you have a chance to look at the line endings?
It is CR/LF.
I added \r\n and that worked for the section. But I guess there needs to be a line to add this when it encounters a \n?
Sample file:
https://helpdesk.itdepartment.com/Download/Working.ini

This is not the original because it contains proprietary info
Is there anything different with the following command line?

sed -n "{:start {s/^Check=Y.*$/Check=N\r\nIDText=Y/;p;t end;n;b start}};{:end n;p; b end}"

(Note the -n switch, it inhibits automatic printing of the so-called "pattern space". Instead, two p commands are added to print it manually.)
It seems to have a problem with how I am writing back to the file.
This is what I have based on your new code:
sed -n "{:start {s/^Check=Y.*$/Check=N\r\nIDText=Y/;p;t end;n;b start}};{:end n;p; b end}" Working.ini > Working2.ini

If I remove "> Working2.ini"  from the list it shows up correctly in the dos window. But I need it to be written back to the file.
Does the following work with file redirection?

sed -n "{:start {s/^Check=Y.*$/Check=N\r\nIDText=Y\r\n/;t end;s/$/\r\n/;p;n;b start}};{:end n;s/$/\r\n/;p; b end}"

(At the end of every line, \r\n is appended.)

Check the line endings of your output file, too. (You can also post it, if you like.)
That removed Check=N and did not add IDText=Y

But it did output properly.

Sample Output:

[Registration]
User=Administrator
Number=HJ-4493MNB
NextID=67145

[Locations]
etc....
sed "1,/Check/s/^Check=Y/Check=N\r\nIDText=Y/; s/$/\r/" Working.ini > Working2.ini

This seems to do it
ASKER CERTIFIED SOLUTION
Avatar of KirillMueller
KirillMueller

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial