Obtain values of a section of a file

I have a configuration file in the following format.

<Title>
 [part1]
  A.File = a
  A.Val = val1
  B.File = a
  B.Val = val1
 [part2]
  A.File = a1
  A.Val = val2 
  B.File = a
  B.Val = val1

I want to extract values from first part only.

 #!/bin/sh 
getCalibDate()
{
 file="/path/of/config/file"
 value=`cat ${file} | grep Val | cut -d'=' -f2`
    for v in $value
    do
            echo $v
    done
}
getCalibDate

Above script will return all the values.
How can I get values from only first part (part1) ?

Asked By: user3153014

||

If you have only 4 lines after [part1] you can use -A4 option with grep:

cat ${file} | grep -A4 "part1" | cut -d'=' -f2`

For general case (more than 4 lines after [part1]) use sed to get the text between two parts:

cat ${file} | sed -n "/part1/,/part2/p" | head -n-1

head is to delete additional part2 at the end

As terdon said you don’t have to use cat, you can do the following instead:

grep -A4 "part1" ${file} | cut -d'=' -f2`

OR:

sed -n "/part1/,/part2/p" ${file} | head -n-1
Answered By: Nidal

You need to use a more sophisticated tool to parse the file. For example, awk:

#!/bin/sh 

getCalibDate()
{
 file="${1}"
 value=$(awk  '/[part/{a++}(a<2 && /Val/){print $NF}' ${file})

    for v in $value
    do
            echo $v
    done
}

getCalibDate ${1}

Here, the variable a is incremented each time a line matches [part. Then, the last field ($NF) is printed when a line matches Val but only if a is less than 2, only if we’re in the 1st section.

Answered By: terdon

and use this:

sed -n -e '/[part1]/,/[part2]/p' FILE |sed -e '1d;$d'| awk -F "=" '{print $2}'

OUTPUT is:

 a
 val1
 a
 val1
Answered By: Baba
sed -n '/part2/q;s/[^=]*=//p' 
<<DATA
<Title>
 [part1]
  A.File = a
  A.Val = val1
  B.File = a
  B.Val = val1
 [part2]
  A.File = a1
  A.Val = val2
  B.File = a
  B.Val = val1
DATA

OUTPUT

 a
 val1
 a
 val1

That should do the trick. It will immediately quit the input file the first time it encounters the string part2 anywhere in the input. This means that it never even attempts to read through the parts of the file you don’t want – which should make it very efficient.

The -n disables auto printing so sed only prints what it is definitely told to print. The only time it is ever definitely told to print is when it can successfully remove a sequence of 0 or more characters that are not = and one character that is an =.

If you wanted to print the whole matched line instead you could do:

sed -n '/part2/q;/=/p'
Answered By: mikeserv

To get the whole lines from the first part:

awk '$1 ~ /^[/ {n++;next} n==1'

To just print the right hand side of the first =:

awk '$1 ~ /^[/ {n++;next} n==1 {sub(/^[^=]*=[[:blank:]]*/,""); print}'
Answered By: glenn jackman

There are some good answers here,
but I see only one that incorporates the Val part of the problem,
and it’s ambiguous whether that is correct. 
I agree that awk is “an amazing tool”, but it’s not necessary here;
I believe that this sed command:

sed -n '/[part1]/,/[part2]/s/.*Val.*=//p' "$file"

probably does what’s desired. 
Like the other sed -e '/[part1]/,/[part2]/p' solutions
(Networker
and Babyy),
this is trivially adaptable to select any section. 
(You do, of course, need to know its name; if you know only its ordinal number,
you can adapt terdon’s answer
or glenn jackman’s answer,
both of which count sections rather than looking for a specific name.) 
If you don’t know the name of section following, you can do

sed -n '/[part42]/,/[part/s…' "$file"

for example.

My only meta-question is regarding the cut -d'=' -f2 part of the question. 
If an input line that we’re extracting data from contains multiple = characters
after Val (i.e., the field value contains = character(s)), e.g.,

Einstein.Val = E=mc^2

then the above cut command will extract only the text between the first and second =
(i.e., the field value, up to (but not including) the first =), e.g.,  E
The sed command I have presented above will extract only the text
after the last = (e.g., mc^2). 
To get everything after the first = (e.g., E=mc^2), use

sed -n '/[part1]/,/[part2]/s/.*Val[^=]*=//p' "$file"

To mimic the behavior of the cut (e.g.,  E), use

sed -n '/[part1]/,/[part2]/s/.*Val[^=]*=([^=]*).*/1/p' "$file"

Note that my approach assumes that the data look
at least generally like the illustration in the question;
i.e., at least one = appears somewhere to the right of the Val string. 
Accordingly, all of my solutions will ignore input like

Girl.Name = Valerie
Valerie Bertinelli

even if it falls between [part1] and [part2].

Categories: Answers Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.