views:

97

answers:

5

I am trying to pull dynamics from a load that I run using bash. I have gotten to a point where I get the string I want, now from this I want to pull certain information that can vary. The string that gets returned is as follows:

Records: 2910 Deleted: 0 Skipped: 0 Warnings: 0

Each of the number can and will vary in length, but the overall structure will remain the same. What I want to do is be able to get these numbers and load them into some bash variables ie:

RECORDS=??
DELETED=??
SKIPPED=??
WARNING=??

In regex I would do it like this:

Records: (\d*?) Deleted: (\d*?) Skipped (\d*?) Warnings (\d*?)

and use the 4 groups in my variables.

+1  A: 

Built-in read command will do the trick:

read TMP1 RECORDS TMP2 DELETED TMP3 SKIPPED TMP4 WARNING

Update: You can also use set:

set $line
RECORDS=$2
DELETED=$4
SKIPPED=$6
WARNING=$8
Bolo
read is to catch user input, im not inputting this manually, that string is set to a variable called `$r`
Russ Bradberry
@Russ Here's an updated answer that works with strings too.
Bolo
@Russ: `read` can get values from standard input: `s="foo bar baz"; read a b c <<< $s`
Dennis Williamson
A: 

You can try something with 'sed' or 'cut' depending on the structure of the line like this:

#!/bin/sh                                                                       

DYNAMIC="Records: 2910 Deleted: 1 Skipped: 2 Warnings: 3"

RECORDS=`echo "$DYNAMIC" | sed 's/.*Records: \([0-9]*\).*/\1/g'`
DELETED=`echo "$DYNAMIC" | sed 's/.*Deleted: \([0-9]*\).*/\1/g'`
SKIPPED=`echo "$DYNAMIC" | sed 's/.*Skipped: \([0-9]*\).*/\1/g'`
WARNINGS=`echo "$DYNAMIC" | sed 's/.*Warnings: \([0-9]*\).*/\1/g'`

echo "Records $RECORDS"
echo "Deleted $DELETED"
echo "Skipped $SKIPPED"
echo "Warnings $WARNINGS"

echo "$DYNAMIC" | cut -d " " -f2
echo "$DYNAMIC" | cut -d " " -f4
echo "$DYNAMIC" | cut -d " " -f6
echo "$DYNAMIC" | cut -d " " -f8
rmarimon
Too complicated, I prefer Bolo's solution.
Hai Vu
+4  A: 

You can use regex matching in Bash versions >= 3.2:

[[ $line =~ ([[:digit:]]+).*([[:digit:]]+).*([[:digit:]]+).*([[:digit:]]+) ]]

RECORDS=${BASH_REMATCH[1]}
DELETED=${BASH_REMATCH[2]}
SKIPPED=${BASH_REMATCH[3]}
WARNING=${BASH_REMATCH[4]}
Dennis Williamson
Great answer. I would choose you even though I wrote another answer. This is some functionality of bash that I didn't know about.
rmarimon
@rmarimon, this works, but only when your line is exactly that as shown every time. If there are more data, it won't work.
ghostdog74
+1  A: 

Here's a shell function you can use that just creates a number of name/value pairs. It assumes things are formatted as you said, but is easy to change:

parseline() {
    while [ $# -ge 2 ] ; do
        eval $(echo $1 | tr -d : | tr '[a-z]' '[A-Z]')="$2"
        shift 2
    done
}

Execute it like:

$ parseline Records: 2910 Deleted: 0 Skipped: 0 Warnings: 0
$ echo $RECORDS
2910
$ echo $WARNINGS
0
camh
A: 
#!/bin/bash
s="Records: 2910 Deleted: 0 Skipped: 0 Warnings: 0"
s=${s//: /=}
for i in $(printf ${s// /"\n"})
do
 eval $i
done

echo "Records: $Records"
echo "Deleted: $Deleted"
echo "Skipped: $Skipped"
echo "Warnings: $Warnings"

output

$ ./shell.sh
Records: 2910
Deleted: 0
Skipped: 0
Warnings: 0
ghostdog74