I have an MRTG configuration file containing lines starting with the word "Target". Now in such lines there is a pattern starting with the character "#", and ending with character ":".

A sample line could look like these (note two types but start/end markers are still the same):

   Target[]: #Gi1/1:public@

   Target[]: #Gi1/31:public@

What I need is for sed to find these lines and replace the pattern "#Gix/n:" with "ifInErrors#Gix/n&ifInErrors#Gix/n:", where x=1-9, n=1-48.

So the two sample lines shown above would be modified to these:

Target[]: ifInErrors#Gi1/1&ifInErrors#Gi1/1:public@

Target[]: ifInErrors#Gi1/31&ifInErrors#Gi1/31:public@

What you need is a capturing group - you capture what you need in parentheses, and can reference it in the substitution. Like so:

 grep ^[[:space:]]*Target file | sed 's/\(#Gi[1-9]\/[1-9][0-9]*\):/ifInErrors\1\&ifInErrors\1:/'
| improve this answer | |
sed '/Target/s/\(#Gi[0-9]*_[0-9]*:\)/ifInErrors\1\&ifInErrors\1/' input.txt

sed '/Target/ is equivalent to grep Target | sed, except it involves one less process & one less pipe.

s/ means 'substitution', the most common sed command; s/foo/bar/ would replace instances of the string foo with bar, for example.

/\(#Gi[0-9]*\/[0-9]*:\) ... the brackets (which need to be escaped with a \) tell sed to mark everything between them as \1 (or \2 for the second marked pattern, \3 for the third etc). [0-9]* means 'any number of numbers', and \/ is an escaped / (it needs to be escaped because I'm using / as the separator for sed; if you use another separator, like |, then you wouldn't need to escape the /). So #Gi[0-9]*\/[0-9]*: is a pattern meaning 'start with #, followed by Gi, then any number of numbers, then /, then any number of numbers, ending with :'.

So \1 matches whatever string is detected by the pattern #Gi[0-9]*\/[0-9]*: In the first string given in the question,

Target[]: #Gi1/1:public@
##  The pattern #Gi[0-9]*\/[0-9]*: will match the substring

...therefore /ifInErrors\1\&ifInErrors\1/ tells sed 'replace #Gi1/1: with ifInErrors#Gi1/1:&ifInErrors#Gi1/1:'.

Some extra stuff: if you wanted to just print the lines that begin with 'Target', doing the sed substitution, you could use this line:

sed -n '/Target/s/\(#Gi[0-9]*\/[0-9]*:\)/ifInErrors\1\&ifInErrors\1/p'

-n tells sed 'don't print the output', and the p at the end tells it to print the lines sed is working on.

If you wanted to over-write your original file, you would use this:

sed -i '/Target/s/\(#Gi[0-9]*\/[0-9]*:\)/ifInErrors\1\&ifInErrors\1/'
| improve this answer | |
  • Can you elaborate a little? This isn't really an answer without text explaining it. – Seth Jan 31 '13 at 4:44
  • @Seth Haha, fair enough, will edit in a explanation in a minute – evilsoup Jan 31 '13 at 14:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.