Reputation: 1
I've spent the last 90 minutes Googling this problem so I hope I am not asking a question that has been asked several times before.8
I am currently trying to parse a log file and need a specific value from a line. Text file contents:
read: 4163419415 0 0 4163419415 0 4395.007 0
read: 4163419415 0 0 4163419415 0 4395.007 0
read: 4163419415 0 0 4163419415 0 4395.007 1
read: 4163419415 0 0 4163419415 0 4395.007 0
I need to grab that last value (which can be variable) and do some checking against it.
COUNTER=1
while [ $COUNTER -lt 26 ]; do
ECREAD=$(awk '/read:/{i++}i=='$COUNTER'{print $8; exit}' ./txt.file)
echo $ECREAD
if [ "$ECREAD" > 0 ]
then
echo "fail"
fi
let COUNTER=COUNTER+1
done
My problem is the if statement is always true regardless of what value $ECREAD is. I have tried
[[ $ECREAD =~ ^-?[0-9]+$ ]] && echo integer
to verify that the variable is an integer.
I have also tried removing any white space that may be at the end of the variable by piping the awk portion of the command into sed 's/ *$//'
AND sed 's/^ *//'
AND tr -d ' '
I have tried changing the [] around the IF statement into [[]]
AND (( ))
I have tried changing the >
symbol into the -gt
symbol.
Upvotes: 0
Views: 1193
Reputation: 84551
Here a pure bash solution can be just as easy as parsing the file with awk
. read
has the ability to read the space
, tab
or newline
delimited text (default: internal field separator $IFS
) without changing the delimiter. You can then just read the first seven values into a junk variable and discard, leaving only the ecread
value you are interested in.
The awk
solution is fine as well, but if you are working in bash, it can fill your need as well without relying on an external process:
#!/bin/bash
## accept filename as first argument to script (default dat/ecread.dat)
fn="${1:-dat/ecread.dat}"
## validate file is readable
[ -r "$fn" ] || {
printf "error: file not readable '%s'. Usage: %s <filename> (dat/ecread.dat)\n\n" "$fn" "${0//*\//}"
exit 1
}
declare -i counter=1 # declare counter as int, set to 1
## read each line in data-file and discard first 7 values (while counter < 26)
while [ "$counter" -lt 26 ] && read a a a a a a a ecread || [ -n "$ecread" ]; do
printf " ecread: %s" "$ecread"
## test ecread > 0, if so fail, if not OK
[ "$ecread" -gt 0 ] && printf " -- fail\n" || printf " -- OK\n"
counter+=1
done <"$fn"
exit 0
output:
$ bash ecread.sh
ecread: 0 -- OK
ecread: 0 -- OK
ecread: 1 -- fail
ecread: 0 -- OK
Upvotes: 0
Reputation: 113834
Suppose that we have inputfile
. We want to examine only the first 24 lines. If any of those lines start with read:
and have a last column that is greater than zero, then we want to print Fail
.
If that is the case, then:
$ awk '/^read:/ && $NF > 0 {print "Fail";} NR>=24{exit;}' inputfile
Fail
How it works
/^read:/ && $NF > 0 {print "Fail";}
For any row that starts with read:
and whose last column, $NF
, is greater than zero, then Fail
is printed.
NR>=24{exit;}
awk
makes available a record (line) counter called NR
. After line number 24 has been processed, the program will exit without reading further.
bash
loopIf the goal is to use awk one line at a time inside of a bash loop, then try:
for ((counter=1; counter<26; counter++))
do
ecread=$(awk -v num=$counter '/read:/ && NR==num {print $8} NR==num{exit;}' ./txt.file)
echo ecread=$ecread
if [ "$ecread" ] && [ "$ecread" -gt 0 ]
then
echo "fail"
fi
done
How it works
for ((counter=1; counter<26; counter++)); do
This starts a bash loop over counter.
ecread=$(awk -v num=$counter '/read:/ && NR==num {print $8} NR==num{exit;}' ./txt.file)
This passes in the value of the bash variable counter
into awk as the variable num
. If line number num
contains read:
, then the value of field 8 is printed. After processing line number num
, awk exits.
if [ "$ecread" ] && [ "$ecread" -gt 0 ]
This starts an if
-then
statement. The then
part is executed if (a) ecread
has a non-empty value and (b) if that non-empty value is greater than zero.
Try:
ECREAD=$(awk '/read :/{print $8; exit}' ./txt.file)
echo ECREAD=$ECREAD
if [ 1 = "$(echo "$ECREAD > 0" | bc)" ]
then
echo "fail"
fi
/read:/
does not match anything. The input, at least as displayed in the question, has a space between read
and :
. Thus, the test is changed to /read :/
The purpose of the code {i++}o==$COUNTER'
was not clear and it was removed.
The value of ECREAD
in the sample input is a float: 4395.007. The shell only does integer arithmetic. However, bc
handles floats well. So the test was converted to use bc
.
When doing comparisons with the shell test command, [
, The symbols >
and <
compare string values lexicographically. For numeric tests, one can use the mnemonically-named -eq
, -ne
, -lt
, -le
, -gt
, or -ge
.
The output from the above code on the provided sample input is:
ECREAD=4395.007
fail
On the chance that there is a misplaced space in the sample input, consider this alternative. Assume that the input looks like:
read: 4163419415 0 0 4163419415 0 4395.007 0
Now, the 8th field is not a float but a zero. In this case, bc
is not needed and the code can be simplified to:
ECREAD=$(awk '/read:/{print $8; exit}' ./txt.file)
echo ECREAD=$ECREAD
if [ "$ECREAD" -gt 0 ]
then
echo "fail"
fi
The output from the above code is:
ECREAD=0
Upvotes: 2
Reputation: 753635
The assignment line is a bit of a mess:
ECREAD=$(awk '/read:/{i++}o==$COUNTER'{print $8; exit}' ./txt.file)
There are three single quotes and no backslashes, which makes for trouble. You probably need:
ECREAD=$(awk '/read:/ {i++} o==$COUNTER {print $8; exit}' ./txt.file)
That's syntactically valid. It isn't clear that it does what you expect. The variable i
is incremented if the pattern matches (it doesn't match your sample data) but is otherwise unused. The test o == $COUNTER
compares the unset variable o
with $0
(because COUNTER
is an unset variable, and hence evaluates to 0). Since the conditions is not true, the printing is not executed. This might do what you intended:
ECREAD=$(awk '/^read :/ { print $8; exit}' ./txt.file)
Your shell 'if
' statement is a big mess:
[ if "$ECREAD" > 0 ]
then
echo "fail"
fi
It should be:
if [ "$ECREAD" -gt 0 ]
then
echo "fail"
fi
or:
if [[ "$ECREAD" -gt 0 ]]
then
echo "fail"
fi
Upvotes: 0
Reputation: 26667
You can try something like
$ ECREAD=$(awk '$1~/read/{print $7}' input )
$ if [ $ECREAD -gt 0 ]
> then
> echo fail
> else
> echo pass
> fi
pass
Upvotes: 0