Search code examples
bashshellif-statementgreptail

Grep issues with if statement in shell script


I'm having an issue with tail & grep in shell script if statement. If I run tail -5 mylog.log | grep -c "Transferred: 0" in shell, it runs as it should, but in this shell script if statement:

# Parse log for results
if [ tail -1 "$LOGFILE" | grep -c "Failed" ] ; then
        RESULT=$(tail -1 "$LOGFILE")
elif [ tail -5 "$LOGFILE" | grep -c "Transferred:            0" ] ; then
        RESULT=""
else
        RESULT=$(tail -5 "$LOGFILE")
fi

I get

... [: missing `]'
grep: ]: No such file or directory

for both of the grep lines.

It's clearly to do with the closing ] being seen as part of the grep (and thus missing) but I'm using the correct whitespace so I can't figure out what's going on? What am I doing wrong here?

Thanks, PJ


Solution

  • Immediate Issue / Immediate Fix

    Take out the brackets.

    if tail -1 "$logfile" | grep -q "Failed" ; then
    

    [ is not part of if syntax. Rather, it's a synonym for the command named test (which is typically both available as a shell builtin and an external binary, like /bin/test or /usr/bin/test).

    Thus, your original code was running [ tail -1 "$logfile", and piping its result to grep -q "Failed" ]. The first [ was failing because it didn't see an ending ] -- which is mandatory when invoked by that name rather than with the name test -- and also because its parameters weren't a test it knew how to parse; and the second grep didn't know what the ] it was being piped meant, trying to find a file by that name.


    Other Notes

    Try to run external commands -- like tail -- as little as possible. There's a very significant startup cost.

    Consider the following, which runs tail only once:

    #!/bin/bash
    #      ^^^^- IMPORTANT: bash, not /bin/sh
    
    last_5_lines="$(tail -5 "$logfile")"
    last_line="${last_5_lines##*$'\n'}"
    if [[ $last_line = *Failed* ]]; then
      result=$last_line
    elif [[ $last_5_lines =~ 'Transferred:'[[:space:]]+'0' ]]; then
      result=''
    else
      result=$last_5_lines
    fi