问题
This is probably pretty basic, I want to read in a occurrence file.
Then the program should find all occurrences of "CallTilEdb"
in the file Hendelse.logg
:
CallTilEdb 8 CallCustomer 9 CallTilEdb 4 CustomerChk 10 CustomerChk 15 CallTilEdb 16
and sum up then right column. For this case it would be 8 + 4 + 16, so the output I would want would be 28
.
I'm not sure how to do this, and this is as far as I have gotten with vistid.sh
:
#!/bin/bash
declare -t filename=hendelse.logg
declare -t occurance="$1"
declare -i sumTime=0
while read -r line
do
if [ "$occurance" = $(cut -f1 line) ] #line 10
then
sumTime+=$(cut -f2 line)
fi
done < "$filename"
so the execution in terminal would be
vistid.sh CallTilEdb
but the error I get now is:
/home/user/bin/vistid.sh: line 10: [: unary operator expected
回答1:
You have a nice approach, but maybe you could use awk
to do the same thing... quite faster!
$ awk -v par="CallTilEdb" '$1==par {sum+=$2} END {print sum+0}' hendelse.logg
28
It may look a bit weird if you haven't used awk so far, but here is what it does:
-v par="CallTilEdb"
provide an argument toawk
, so that we can usepar
as a variable in the script. You could also do-v par="$1"
if you want to use a variable provided to the script as parameter.$1==par {sum+=$2}
this means: if the first field is the same as the content of the variablepar
, then add the second column's value into the countersum
.END {print sum+0}
this means: once you are done from processing the file, print the content ofsum
. The+0
makesawk
print0
in casesum
was not set... that is, if nothing was found.
In case you really want to make it with bash, you can use read
with two parameters, so that you don't have to make use of cut
to handle the values, together with some arithmetic operations to sum the values:
#!/bin/bash
declare -t filename=hendelse.logg
declare -t occurance="$1"
declare -i sumTime=0
while read -r name value # read both values with -r for safety
do
if [ "$occurance" == "$name" ]; then # string comparison
((sumTime+=$value)) # sum
fi
done < "$filename"
echo "sum: $sumTime"
So that it works like this:
$ ./vistid.sh CallTilEdb
sum: 28
$ ./vistid.sh CustomerChk
sum: 25
回答2:
first of all you need to change the way you call cut:
$( echo $line | cut -f1 )
in line 10 you miss the evaluation:
if [ "$occurance" = $( echo $line | cut -f1 ) ]
you can then sum by doing:
sumTime=$[ $sumTime + $( echo $line | cut -f2 ) ]
But you can also use a different approach and put the line values in an array, the final script will look like:
#!/bin/bash
declare -t filename=prova
declare -t occurance="$1"
declare -i sumTime=0
while read -a line
do
if [ "$occurance" = ${line[0]} ]
then
sumTime=$[ $sumtime + ${line[1]} ]
fi
done < "$filename"
echo $sumTime
回答3:
For the reference,
id="CallTilEdb"
file="Hendelse.logg"
sum=$(echo "0 $(sed -n "s/^$id[^0-9]*\([0-9]*\)/\1 +/p" < "$file") p" | dc)
echo SUM: $sum
prints
SUM: 28
- the
sed
extract numbers from a lines containing the given id, suchCallTilEdb
- and prints them in the format
number +
- the
echo
prepares a string such0 8 + 16 + 4 + p
what is calculation in RPN format - the dc do the calculation
another variant:
sum=$(sed -n "s/^$id[^0-9]*\([0-9]*\)/\1/p" < "$file" | paste -sd+ - | bc)
#or
sum=$(grep -oP "^$id\D*\K\d+" < "$file" | paste -sd+ - | bc)
- the sed (or the grep) extracts and prints only the numbers
- the paste make a string like
number + number + number
(-d+
is a delimiter) - the
bc
do the calculation
or perl
sum=$(perl -slanE '$s+=$F[1] if /^$id/}{say $s' -- -id="$id" "$file")
sum=$(ID="CallTilEdb" perl -lanE '$s+=$F[1] if /^$ENV{ID}/}{say $s' "$file")
回答4:
Awk translation to script:
#!/bin/bash
declare -t filename=hendelse.logg
declare -t occurance="$1"
declare -i sumTime=0
sumtime=$(awk -v entry=$occurance '
$1==entry{time+=$NF+0}
END{print time+0}' $filename)
来源:https://stackoverflow.com/questions/25742693/reading-a-file-in-a-shell-script-and-selecting-a-section-of-the-line