Reputation: 388
I'm struggling even with all the examples available on stackoverflow and google.
Basically i have the following text
/start r.start ""
GAIN 0x256 __POSITIVE 1 FOO
OTHER
OTHER
/start MACRO
200
CODE "r.start" 0x256 0x2 10 0xA3
/end MACRO
OTHER
/end
and i need to read through this file searching for a name e.g. r.start which is passed as $1 and substitute e.g. 0x256 with a value that i pass as $2. There a two instance to substitute, line 2 and line 7.
Things i know:
Till now i've reached this point
pattern="N;s\s\/start r.start \"\"\n GAIN 0x\(.*\)"
replacement"\/start r.start \"\"\n GAIN 0x82"
sed -e "$pattern/$replacement/p" test.txt
but i get nothing. I was also able to substitute the first line but for whatever reason it pasted me the first two lines twice on top of each other
the expected value assuming the following call
./run.sh r.start 0x284569
should be
/start r.start ""
GAIN 0x284569 __POSITIVE 1 FOO
OTHER
OTHER
/start MACRO
200
CODE "r.start" 0x284569 0x2 10 0xA3
/end MACRO
OTHER
/end
Here's my best shot for the second part
var="r.start"
val="0x48209F82"
pattern="\(CODE \"$var\" \).*\(.*\)"
replacement="\1$val\2"
sed "s/$pattern/$replacement/g" test.txt
The problem is that it is deleting everything after the value substitution. I can't put in \2 the following chars
EDIT:
By doing the following
var="r.start"
val="0x48209F82"
pattern="\(CODE \"$var\" \).*\(\s.*\s.*\s.*\)"
replacement="\1$val\2"
sed "s/$pattern/$replacement/g" test.txt
I get what i want but it feels a little bit dirty, how do i reduce the last part in case of a variable number of char? Can i just somehow match everything till end of line?
Upvotes: 0
Views: 159
Reputation: 3671
How about something like the following? It uses a sed
range to select everything between the /start
and /end
, and within the range uses a block to substitute the value for lines which match GAIN
and CODE
.
$ cat foo.txt
/start r.start ""
GAIN 0x256 __POSITIVE 1 FOO
OTHER
OTHER
/start MACRO
200
CODE "r.start" 0x256 0x2 10 0xA3
/end MACRO
OTHER
/end
$ sed '\#/start r\.start#,\#/end#{/\(GAIN\|CODE "r\.start"\)/s/0x[a-fA-F0-9]\+/0x284569/}' foo.txt
/start r.start ""
GAIN 0x284569 __POSITIVE 1 FOO
OTHER
OTHER
/start MACRO
200
CODE "r.start" 0x284569 0x2 10 0xA3
/end MACRO
OTHER
/end
The sed
script looks like this when formatted nicely:
\#/start r\.start#,\#/end# {
/\(GAIN\|CODE "r\.start"\)/s/0x[a-fA-F0-9]\+/0x284569/
}
Note
\#...#
instead of /.../
for the range patterns, so we don't have to quote slashes/patten1/s/pattern2/string/
to replace pattern2
only for lines containing pattern1
{...}
block so that the substitution only applies between /start
and /end
You can parameterise the pattern and value like so:
#!/bin/bash
var='r\.start'
val='0x48209F82'
sed '\#/start '$var'#,\#/end#{/\(GAIN\|CODE "'$var'"\)/s/0x[0-9a-fA-F]\+/'$val'/}' foo.txt
Upvotes: 2
Reputation: 91518
Here is a perl way:
#!/usr/bin/perl
use strict;
use warnings;
# retrieve the 2 parameters
my $start = shift @ARGV or die "missing 1rst arg";
my $repl = shift @ARGV or die "missing 2nd arg";
# input file
open my $fh_in, '<', 'file.txt' or die "$!";
# output file
open my $fh_out, '>', 'output' or die "$!";
# loop through input file
while(<$fh_in>) {
# if we are between /start {1srt parameter} and /end
if (/^ {4}\/start\h+$start/ ... /^ {4}\/end\h*$/) {
# substitute 0x.... by {2nd parameter}
s/^(?: {6}GAIN | {8}CODE "$start" )\K0x\w+/$repl/;
}
print $fh_out $_;
}
In action:
cat file.txt
/start other.start ""
GAIN 0x256 __POSITIVE 1 FOO
OTHER
OTHER
/start MACRO
200
CODE "r.start" 0x256 0x2 10 0xA3
/end MACRO
OTHER
/end
/start r.start ""
GAIN 0x256 __POSITIVE 1 FOO
OTHER
OTHER
/start MACRO
200
CODE "r.start" 0x256 0x2 10 0xA3
/end MACRO
OTHER
/end
./test.pl r.start 0x123456
cat output
/start other.start ""
GAIN 0x256 __POSITIVE 1 FOO
OTHER
OTHER
/start MACRO
200
CODE "r.start" 0x256 0x2 10 0xA3
/end MACRO
OTHER
/end
/start r.start ""
GAIN 0x123456 __POSITIVE 1 FOO
OTHER
OTHER
/start MACRO
200
CODE "r.start" 0x123456 0x2 10 0xA3
/end MACRO
OTHER
/end
Upvotes: 0
Reputation: 58578
This might work for you (GNU sed):
sed -E '/^ \/start r\.start /{:a;N;/^ \/end$/M!ba;s/^( GAIN | CODE "r\.start" )0x\S+/\10x284569/Mg}' file
Gather up lines between /start
and /end
and using pattern matching replace the desired values.
The solution may be placed in a function:
f () { sed -E '/^ \/start '"$1"' /{:a;N;/^ \/end$/M!ba;s/^( GAIN | CODE "'"$1"'" )0x\S+/\1'"$2"'/Mg}' "$3"; }
And called:
f r\\.start 0x284569 file
Upvotes: 0
Reputation: 1
You want sed for this, and don't need a script:
Assuming the text is a file called the_text:
sed "s/0x256/REPLACETEXT/g" the_text
If you ant to do that with out echoing out the text then add a -i
sed -i "s/0x256/REPLACETEXT/g" the_text
It is possible to daisy chain these commands or embed them into single script, this one echoes to the standard out:
#!/bin/bash
sed "s/0x256/${2}/g" $1
sed "s/0x256/${2}/g" $1
Upvotes: -1