Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

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?

share|improve this question

6 Answers 6

up vote 2 down vote accepted

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.

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

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
share|improve this answer
    
Could you explain line two and three of your awk command? –  erik Mar 4 at 21:23

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

share|improve this answer
    
Thanks. That would save me lot of code lines. –  Vinay Challuru Mar 3 at 17:34
    
When I try to do this, I get an error saying that the input line number must be less than 199. –  Vinay Challuru Mar 5 at 10:04
    
@VinayChalluru can you show me output with command, use paste.ubuntu.com –  Rahul Patil Mar 5 at 10:05
    
Apologies. I added an $ before NR and that caused the error. –  Vinay Challuru Mar 5 at 11:05
    
@VinayChalluru It's OK. that's Good you tried/tested each ans and learn something new.. :D –  Rahul Patil Mar 5 at 11:39

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.

share|improve this answer
    
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 Challuru Mar 3 at 17:11
    
@VinayChalluru See the answer above for how you could modify the sed expression. –  devnull Mar 3 at 17:12
    
This answers my question I guess. Let me try and let you know. –  Vinay Challuru Mar 3 at 17:22
    
for word boundaries , grep with -w flag ? isn't it ? –  Rahul Patil Mar 3 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 at 17:33

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.

share|improve this answer

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
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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