confusified
confusified

Reputation: 2330

Bash - Parsing and variables

case 4.1
Info for unit 1 starts now
info1
info2
info3
info5  - the one I want
info6
info7
Info for unit 2 starts now
info1
info2
info3
info5  - the one I want
info6
info7
endcase 4.1

The info for the 2 units are printed out over 1000 times in the file.

My algorithm is as follows:

while read line
do
    if line contains unit1
    then current_unit=1
    if line contains unit2
    then current_unit2

    if line contains info5
    then 
         if current_unit = 1
            then unit1_val = *the relevant info from this line*
         elif current_unit = 2 
             then unit2_val = *the relevant info from this line*

    if both unit1_val > 20 && unit2_val > 20
    then pass

Short version: pull the values i need, if at some point both values are over a certain value, test passed. I'm also trying to do this using Bash

Edit for clarity: The problem that I', having is passing variables in and out of if statements. My parsing and comparisons are fine, however When i get to the last if, the values are not there, because they are local to the if - fi they come from (or dont come from, as the case may be)

edit 2:

    if [[ $line == *"info5"* ]]
    then
            CURRENT_UNIT=5
    fi

    if [[ $line = *"info6"* ]]
    then
            CURRENT_UNIT=6     
    fi

    if [[ $line =~ "text i want" ]]
    then
            if [[ $CURRENT_UNIT -eq 5 ]]
            then
                    UNIT_5_MEM=$(awk '/Used heap/ { gsub(/M/, " "); print $4 }')
            elif [[ $CURRENT_VC -eq 6 ]]
            then    UNIT_6_MEM=$(awk '/Used heap/ { gsub(/M/, " "); print $4 }')
            fi
    fi

    if [[ $UNIT_5_MEM -gt 20 && $UNIT_6_MEM -gt 20 ]]
    then
            echo "Passed"
    fi

Upvotes: 0

Views: 189

Answers (2)

ghoti
ghoti

Reputation: 46896

I gather that the reason you posted the question is because variables set inside your while loop seem to disappear once the while loop finishes.

This is because when you execute the while loop as part of a pipeline, it runs in a subshell, and when the subshell exits, the environment of the parent shell remains unchanged, unaffected by whatever was happening in the subshell.

You can get around this in bash by getting your input data using redirection or process substitution rather than a pipeline. For example, this doesn't work:

cat inputfile | while read line; do
  case "$line" in
    foo*) output=$line ;;
  esac
done
echo "output=$output"

Whereas this does work:

while read line; do
  case "$line" in
    foo*) output=$line ;;
  esac
done < inputfile
echo "output=$output"

Here's what I came up with:

#!/bin/bash

declare -A output

while read line; do
    case "$line" in
        *unit*)
            unit=$(awk '{print $4}' <<<"$line")
            ;;
        info5*)
            output[$unit]="$line"
            echo "FOUND: unit=$unit, line=$line" >&2
            ;;
    esac
done < inp1

echo "Output 1:"
printf "%s\n" "${output[@]}"

### Alternately:

echo "Output 2:"
for ((i=${#output[@]}; i > 0; i--)); do
    echo "unit=$i, line=${output[$i]}"
done

And the output I got:

FOUND: unit=1, line=info5  - the one I want
FOUND: unit=2, line=info5  - the one I want
Output 1:
info5  - the one I want
info5  - the one I want
Output 2:
unit=2, line=info5  - the one I want
unit=1, line=info5  - the one I want

If you really want to store things to variables like UNIT_5_MEM, I suppose you can, but arrays seem cleaner. Also, without seeing the data you're processing, it's difficult to know what you're trying to achieve with awk, so I've left that out of my answer.

Upvotes: 2

xtofl
xtofl

Reputation: 41519

If you're looking for an easy way to do textual filtering like that, better take a look at sed or [awk][1]. The latter is capable of easy parsing, and storing some state.

Could be something like this (currently untested)

#!/bin/awk
BEGIN {
    current_unit=0;
}

function check_values()
{
   if(values[1]>20 && values[2]>20) {
     print "PASS"
     exit
   }
}

/Info for unit \d starts now/ {
   current_unit=$4;
}

/info5/ {
    values[current_unit]=value;
    check_values();
}

Upvotes: 1

Related Questions