2

This one liner will search for Name: 0602 then replace any instance of Type### with type 700 until next Name is reached.

sed '/Name: R0602/,/Name.*$/ s/type .*;/type 700;/' file2

I am looking to use something similar to this one liner, but I want to use list of names in file1 to search file2. Once a string form file1 is found, it then replaces any instance of string2 until it reaches the end of that name's section, then does the same for the next line in file1.

File1

Name: 0602
Name: 0603
Name: 0604

file2:

# Name: R0601
   Container 4 {
  row 12 type 2 {
     set 1 10 {
         name "C4";
         type 300;
     }
     set 11 20 {
         name "C5";
         type 100;
     }
  set 21 20 {
         name "C6";
         type 300;
     }
  set 31 40 {
         name "C7";
         type 200;
     }
      set 31 40 {
         name "C7";
         type 1200;
     }
  }
}

 # Name: R0602
   Container 5 {
  row 12 type 2 {
     set 1 10 {
         name "C4";
         type 300;
     }
     set 11 20 {
         name "C5";
         type 100;
     }
  set 21 20 {
         name "C6";
         type 300;
     }
  set 31 40 {
         name "C7";
         type 300;
     }
      set 31 40 {
         name "C7";
         type 1100;
     }
  }
}


 # Name: R0603
   Container 6 {
  row 12 type 2 {
     set 1 10 {
         name "C4";
         type 200;
     }
     set 11 20 {
         name "C5";
         type 100;
     }
  set 21 20 {
         name "C6";
         type 300;
     }
  set 31 40 {
        name "C7";
        type 500;
     }
      set 31 40 {
        name "C7";
        type 1100;
     }
  }
}
 # Name: R0604
   Container 6 {
  row 12 type 2 {
     set 1 10 {
         name "C4";
         type 200;
     }
     set 11 20 {
         name "C5";
         type 100;
     }
  set 21 20 {
         name "C6";
         type 300;
     }
  set 31 40 {
        name "C7";
        type 500;
     }
      set 31 40 {
        name "C7";
        type 1100;
     }
  }
}
 # Name: R0605
   Container 6 {
  row 12 type 2 {
     set 1 10 {
         name "C4";
         type 200;
     }
     set 11 20 {
         name "C5";
         type 100;
     }
  set 21 20 {
         name "C6";
         type 300;
     }
  set 31 40 {
        name "C7";
        type 500;
     }
      set 31 40 {
        name "C7";
        type 1100;
     }
  }
}
1

A short awk script

awk '
  NR == FNR               { names["R"$2]; next }
  $2 == "Name:"           { replace = ($3 in names) }
  $1 == "type" && replace { sub(/type .*/, "type 700;") }
  1
' file1 file2

NR and FNR are builtin awk variables. NR counts the total number of lines seen so far. FNR is the number of lines in the current file seen so far. NR == FNR is an awk idiom that means "I'm working in the first data file" -- the only file for which the current record number would equal the total record number.

So, reading the first file, we want to store the "keys", which are in the 2nd column. Storing them as the key of the "names" associative array is a handy place, given the in operator we use later. I'm adding the letter "R" to the key because the 2nd file has that.

When$2 == "Name:", we are at the top of a section. We want to replace the type values if the 3rd word on this line was seen in the first file. ($3 in names) checks if the 3rd word appears as a key in the names associative array. If it's there, then we will perform the replacements for any subsequent lines where the 1st word is "type".

The last line of the script is interesting. 1 is another idiomatic shorthand to instruct awk to print the current line. awk programs are a series of condition {action} pairs: if the condition is met, perform the given actions. The condition can be omitted, in which case the action is performed for every line. The condition can be given without an action block, in which case the default action is to print the current line. awk treats empty strings and zero as false, so 1 is a condition that is always true. When I'm feeling more verbose, I write {print} instead of 1 to make it more obvious.

  • Thank you Glenn! This did exactly what I needed! I need to do some reading on awk! Can you give a bit of explanation on how this works? – Jdubyas Aug 11 '17 at 0:44
  • For reference, the online manual contains all the wisdom. Unsurprisingly, the Getting Started chapter is where to start. – glenn jackman Aug 11 '17 at 1:23
  • Ahh! I'm not sure understand it enough to duplicate it on my own, but I am grasping whats happening now. Thank you very much Glenn! – Jdubyas Aug 11 '17 at 3:15
0

With an GNU awk script as below:

NR == FNR {
                strt=1
        }
strt == 0 {
                if (match($0,/Name/)) {
                        id=substr($0,RSTART,length($0))
                        id=gensub("R","","g",id)
                }
                file2[id]=file2[id]"\n"$0
        }
 FNR == 1 && NR != 1 {
                 strt=0
                 file2[$0]=""
        }
 strt == 1 {
            file1[$0]=$0
        }
 END {
        for (i in file2) {
                if (file1[i] != "") {
                       resp=gensub(/[[:blank:]]{5}type.*;/,"     type 
700;","g",file2[i])
                       print resp
               }
               else {
                    print file2[i]
               }
       }
}

Read the two files into separate arrays (file1,file2) keyed on e.g "Name: 0603". At the end, loop through the array file2 matching against file1. If there is an entry in file1, use gensub to pattern match and replace, otherwise just print the entry in file2.

action with:

 awk -f scriptfile file1 file2
  • Thanks Raman! I ended up using Glenns code below, but once I get a better understanding of awk, I'm going to revisit this to see how it works. – Jdubyas Aug 11 '17 at 0:47

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.