2

I'm trying to create a script that will remove certain parts of a txt file full of status info and other various text. I can't end the main if statement. Also I'm trying to get it to delete the oldest status info by putting the date command into the script that generates the output.txt. Is there a way to make it delete the oldest info. I'm mainly trying to get the if statement to end. Thanks. (Also, I originally had the else if as elif's, but I got the same results.)

./count.sh: line 30: syntax error near unexpected token else' ./count.sh: line 30:else'

WCOUNT=$(wc -l output.txt $1 | awk '{print $1}')

if [[ $WCOUNT -gt 50 ]]; then 

    if [[ "grep CLIENTSTART output.txt" != null ]]; then
        echo $WCOUNT
        sed -i '/\*\*\*CLIENTSTART/,/CLIENTEND\*\*\*/ d' output.txt
        echo $WCOUNT

    else if [[ -n "grep DHCPSTART output.txt" ]]; then          

        echo $WCOUNT
        sed -i '/\*\*\*DHCPSTART/,/DHCPEND\*\*\*/ d' output.txt     
        echo $WCOUNT

    else if [[ -n "grep DNSSTART output.txt" ]]; then
        echo $WCOUNT
        sed -i '/\*\*\*DNSSTART/,/DNSEND\*\*\*/ d' output.txt
        echo $WCOUNT

    else if [[ -n "grep WEBSTART output.txt" ]]; then
        echo $WCOUNT
        sed -i '/\*\*\*WEBSTART/,/WEBEND\*\*\*/ d' output.txt
        echo $WCOUNT

    else
        echo "Cannot help you"
    fi

else
    echo "You're good, homie.  It's under 500"

fi
  • 1
    If $1 (the first commandline argument) is set and is a filename, your wc|awk pipeline actually outputs three numbers which are used as the value of WCOUNT; is that really what you want? If you only want the count of lines in a single file, you don't need awk, just redirection: WCOUNT=$(wc -l <output.txt) . Also your if [[ "grep something output.txt" ]] tests don't actually look at the contents of the file output.txt; after fixing the nesting as answered, all of the tests will/would always succeed regardless of the contents of the file. – dave_thompson_085 Feb 16 '18 at 5:02
  • " I originally had the else if as elif's, but I got the same results" -- changing them to elif, as in Matt's answer should prevent the unexpected token else error. If you're still seeing that message, can you show us the elif version of your script that produces it? – JigglyNaga Feb 16 '18 at 11:23
7

The issue here is that by using else if rather than elif, you are adding nesting to your program, and will need to add more fi statements to terminate the additional conditional statements.

Here is an edited version of your program with slightly different indentation to demonstrate what I mean

WCOUNT=$(wc -l output.txt $1 | awk '{print $1}')

if [[ $WCOUNT -gt 50 ]]; then 
    if [[ "grep CLIENTSTART output.txt" != null ]]; then
        echo $WCOUNT
        sed -i '/\*\*\*CLIENTSTART/,/CLIENTEND\*\*\*/ d' output.txt
        echo $WCOUNT
    else 
        if [[ -n "grep DHCPSTART output.txt" ]]; then          
            echo $WCOUNT
            sed -i '/\*\*\*DHCPSTART/,/DHCPEND\*\*\*/ d' output.txt     
            echo $WCOUNT
        else 
            if [[ -n "grep DNSSTART output.txt" ]]; then
                echo $WCOUNT
                sed -i '/\*\*\*DNSSTART/,/DNSEND\*\*\*/ d' output.txt
                echo $WCOUNT
            else 
                if [[ -n "grep WEBSTART output.txt" ]]; then
                    echo $WCOUNT
                    sed -i '/\*\*\*WEBSTART/,/WEBEND\*\*\*/ d' output.txt
                    echo $WCOUNT
                else
                    echo "Cannot help you"
                fi
            fi
        fi
    fi
else
    echo "You're good, homie.  It's under 500"

fi

Alternatively, you could just use elif

WCOUNT=$(wc -l output.txt $1 | awk '{print $1}')

if [[ $WCOUNT -gt 50 ]]; then 

    if [[ "grep CLIENTSTART output.txt" != null ]]; then
        echo $WCOUNT
        sed -i '/\*\*\*CLIENTSTART/,/CLIENTEND\*\*\*/ d' output.txt
        echo $WCOUNT

    elif [[ -n "grep DHCPSTART output.txt" ]]; then          

        echo $WCOUNT
        sed -i '/\*\*\*DHCPSTART/,/DHCPEND\*\*\*/ d' output.txt     
        echo $WCOUNT

    elif [[ -n "grep DNSSTART output.txt" ]]; then
        echo $WCOUNT
        sed -i '/\*\*\*DNSSTART/,/DNSEND\*\*\*/ d' output.txt
        echo $WCOUNT

    elif [[ -n "grep WEBSTART output.txt" ]]; then
        echo $WCOUNT
        sed -i '/\*\*\*WEBSTART/,/WEBEND\*\*\*/ d' output.txt
        echo $WCOUNT

    else
        echo "Cannot help you"
    fi

else
    echo "You're good, homie.  It's under 500"

fi

(Also, slight nitpick, you're checking if there are more than 50 lines, but your output message indicates that you are checking for 500. While technically, there are under 500 lines, it is a little misleading :p)

EDIT: As others have pointed out, this will fix your syntax error, but there are still other issues with the script. I would recommend reading their comments/answers too.

  • The answer does not address the fact that -n "grep ..." is an odd thing to test (always true as the string grep ... is non-empty). – Kusalananda Feb 16 '18 at 8:24
  • Want to pick up on [[ "grep CLIENTSTART output.txt" != null ]] and its equally broken counterparts, too? – roaima Feb 16 '18 at 8:25
1

The reason you're getting a syntax error is that your else if statements should be elif.

If you give wc -l two files, it will produce three lines of output:

$ wc -l .profile .profile
      30 .profile
      30 .profile
      60 total

This affects the very first if test where $WCOUNT is unquoted, and its expansion introduces another syntax error.

You probably want

WCOUNT=$( wc -l <output.txt )

Additionally, you have a number of tests on strings like "grep DHCPSTART output.txt". These tests will always be true.

To test whether a string is present in a file, use

if grep -Fq 'fixed string' filename; then

e.g.

if grep -Fq 'CLIENTSTART' output.txt; then
   # do something
elif grep -Fq 'DHCPSTART' output.txt; then
   # do something
else
   # do something
fi

The -q stops grep from producing any actual output. Its exit status will tell whether the string was found or not and this is what makes the if statement work (the flag also makes grep stop reading the file at the first match). The -F flag makes grep treat the given pattern as a fixed string rather than as a regular expression.


Suggestion for your script's internals:

tmpfile=$(mktemp)

for string in CLIENT DHCP DNS WEB; do
    if grep -Fq "${string}START" output.txt; then
        sed "/\*\*\*${string}START/,/${string}END\*\*\*/d" \
            output.txt >"$tmpfile"
        break
    fi
done

if [ -s "$tmpfile" ]; then
    mv "$tmpfile" output.txt
else
    echo 'Can not help you'
    rm -f "$tmpfile"
fi

The [ -s "$tmpfile" ] test will succeed if the file $tmpfile has size greater than zero (which it will have if sed was invoked).

The for loop with the break imitates your if ... then ... elif logic but in a more compact way.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.