9

I have a input file FILE1.TXT as below.


11 id1  
12  
13 AGE = 20  
14 NAME = NAME1  
15  
16 id2  
17  
18 AGE = 30  
19 NAME = NAME2  
.  
.  
.  
110 idXYZ  
111  
112 AGE = AGEXYZ  
113 NAME = NAMEXYZ  
114  
115 idZZZ  
116

I want to search all the fields that belong to a particular Id and get the value for NAME

I managed to loop through each Id and formed the below command for each Id as required.

sed -n '/11/,/14/p' FILE1.TXT | grep NAME | awk -F "= " '{print $2}'

The problem here is, I get the output NAME1, in addition to that, I also get NAMEXYZ.

What should be changed so that I only get NAME1 but not NAMEXYZ?

As a workaround, the below commands work.

sed -n '/11/,/14/p' FILE1.TXT | grep NAME | awk -F "= " '{print $2}'|head -1

Is there any 'switch' or am I missing something?

7 Answers 7

6

Use word boundaries:

grep '\bNAME1\b'

would match NAME1 and not NAME1XYZ or XYZNAME1.

Similarly,

sed -n '/11\b/,/14\b/p'

wouldn't match lines containing 111 and 142.


EDIT: It seems that the numbers in the input file are actually line numbers. If that is the case, you could simply say:

sed '11,14!d'

to get the desired lines.

9
  • There is only one NAME between the lines 11 and 14. So, why is sed looking at 111 and 114? How to make it not look in between 111 and 114?
    – Vinay
    Mar 3, 2014 at 17:11
  • @VinayChalluru See the answer above for how you could modify the sed expression.
    – devnull
    Mar 3, 2014 at 17:12
  • This answers my question I guess. Let me try and let you know.
    – Vinay
    Mar 3, 2014 at 17:22
  • for word boundaries , grep with -w flag ? isn't it ? Mar 3, 2014 at 17:31
  • 1
    @RahulPatil Yup, for the above example -w would be equivalent. For the sed example, -w is slightly different.
    – devnull
    Mar 3, 2014 at 17:33
4

You can use AWK

awk 'NR>=13 && NR<=17 && /NAME/{print $NF}' infile

This will look lines between 13 to 17 then search for Name and if match then it will print last word from Name = LastWord

8
  • When I try to do this, I get an error saying that the input line number must be less than 199.
    – Vinay
    Mar 5, 2014 at 10:04
  • @VinayChalluru can you show me output with command, use paste.ubuntu.com Mar 5, 2014 at 10:05
  • Apologies. I added an $ before NR and that caused the error.
    – Vinay
    Mar 5, 2014 at 11:05
  • @VinayChalluru It's OK. that's Good you tried/tested each ans and learn something new.. :D Mar 5, 2014 at 11:39
  • Exactly. There's a lot more ahead. :-)
    – Vinay
    Mar 5, 2014 at 11:51
4

You don't need any other tool for this, sed will easily handle it entire.

sed -nr '/11/,/14/{s/^.*NAME =\s*(\S*).*$/\1/p}' <$infile

That should provide you only with the first sequence of non-whitespace characters following the phrase "NAME = " for every line on which that phrase is found between lines 11 and 14 of any input file sed is fed.

3

If you know the line numbers you want to search (as your Q suggests), tighten the regex so that you don't match unwanted lines.

For example, change:

sed -n '/11/,/14/p' | grep NAME | awk -F "= " '{print $2}'

to

sed -n '/^11 /,/^14 /p' | grep NAME | awk -F "= " '{print $2}'

The ^ will match the beginning of the line and a space after the number guarantees that the specific line number will be matched, and you won't process unwanted blocks.

4
  • That would help. But, How can I match ^(random no of spaces)11 ?
    – Vinay
    Mar 3, 2014 at 17:13
  • 1
    @VinayChalluru use sed -n '/^\s*11 /,/^\s*14 /p'
    – casey
    Mar 3, 2014 at 17:17
  • 1
    it can be short hand using sed -n '/^11 /,/^14 /p' | awk '/NAME/{print $NF}' have you tried this ? Mar 3, 2014 at 17:38
  • @RahulPatil Yes, It works.
    – Vinay
    Mar 5, 2014 at 10:07
3

sed is not the right tool for this job. Use awk where you can specify the id you're looking for and print the next NAME that appears.

awk -v id="id2" '
    $NF == id {have_id = 1} 
    have_id && $0 ~ /NAME/ {print $NF; exit}
' filename
1
  • Could you explain line two and three of your awk command?
    – erik
    Mar 4, 2014 at 21:23
1

you can print those lines which contain matching pattern using sed as follows:

sed -n '/pattern/p'  Filename
  • -n - these options disable this automatic printing, and sed only produces output when explicitly told to via the p command.

  • p - print

0

generic version not based on line number but id reference

sed -n '1h;1!H;
$ {
  x
  s/.*/&\^J/
: clean
#  put your ID pattern here in place of id9
  s/.*\(id9 *\n.*\)id[0-9]\{1,\} *\n.*/\1/
  t clean
  s/.*NAME = \([^[:cntrl:]]*\)\n.*/\1/
  p
  }' YourFile
  1. load the whole file
  2. clean section not part of the id group (recursive)
  3. just take NAME content value in the group
  4. print the result

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .