Iqbal honnur
Iqbal honnur

Reputation: 68

Arithmetic operation fails in Shell script

Basically I'm trying to check if there are any 200 http responses in the log, in last 3 line. but I'm getting the below error. Because of this the head command is failing..Please help

    LINES=`cat http_access.log |wc -l`
    for i in  $LINES $LINES-1 $LINES-2

do
        echo "VALUE $i"
        head -$i http_access.log | tail -1 > holy.txt
        temp=`cat holy.txt| awk '{print $9}'`

        if [[ $temp == 200 ]]
        then
        echo "line $i has 200 code at "
        cat holy.txt | awk '{print $4}'
        fi
done

Output:

VALUE 18 line 18 has 200 code at [21/Jan/2018:15:34:23 VALUE 18-1 head: invalid trailing option -- - Try `head --help' for more information.

Upvotes: 1

Views: 240

Answers (2)

PesaThe
PesaThe

Reputation: 7499

You got the why from JohnKugelman's answer, I will just propose a simplified code that might work for you:

while read -ra fields; do
    [[ ${fields[9]} = 200 ]] && echo "Line ${fields[0]} has 200 code: ${fields[4]}"
done < <(cat -n http_access.log | tail -n 3 | tac)
  • cat -n: Numbers lines of the file
  • tail -n 3: Prints 3 last lines. You can just change this number for more lines
  • tac: Prints the lines outputted by tail in reversed order
  • read -ra fields: Reads the fields into an array $fields
  • ${fields[0]}: The line number
  • ${fields[num_of_field]}: Individual fields

You can also use wc instead of numbering using cat -n. For larger inputs, this will be slightly faster:

lines=$(wc -l < http_access.log)
while read -ra fields; do
    [[ ${fields[8]} = 200 ]] && echo "Line $lines has 200 code: ${fields[3]}"
    ((lines--))
done < <(tail -n 3 http_access.log | tac)

Upvotes: 1

John Kugelman
John Kugelman

Reputation: 361605

Use $((...)) to perform arithmetic.

for i in $((LINES)) $((LINES-1)) $((LINES-2))

Without it, it's attempting to run the commands:

head -18 http_access.log
head -18-1 http_access.log
head -18-2 http_access.log

The latter two are errors.

A more flexible way to write the for loop would be using C-style syntax:

for ((i = LINES - 2; i <= LINES; ++i)); do
    ...
done

Upvotes: 3

Related Questions