Search code examples
bashshellcatwc

Getting the line count of a file in a shell script with wc failing


my script check if the arguments are files or folders if it is a file, he count the number of lines after that, if the number of lines is great then 20 or less he do some instructions the problem is in this instructionn= cat $a | wc -l

My script:

#!/usr/bin/env bash
echo 'Hello this is the test of' `date`
echo 'arguments number is ' $#
if [ $# -eq 4 ]
then
    for a in $@
    do
    if [ -d $a ]
    then
        ls $a > /tmp/contenu
        echo "contenu modified"
    elif [ -f $a ]
        then
#        this instruction must set a numeric value into n
            echo "my bad instruction"
            n=  cat $a | wc -l
            echo "number of lines  = " $n
#        using the numeric value in a test (n must be numeric and takes the number of lines in the current file)
            if [ $n -eq 0  ]
            then
                echo "empty file"
            elif [ $n -gt 20 ]
            then
                echo ` head -n 10 $a `
            else
                cat $a
            fi
    else
        echo "no file or directory found"
    fi
    done
else
echo "args number must be 4"
fi

This is the output of the execution of the incorrect instruction

my bad instruction
5
number of lines  = 
ExamenEx2.sh: line 19: [: -eq : opérateur unaire attendu

Solution

  • The line n= cat $a | wc -l is an offending instruction. Always remember that bash shell scripting is extremely case-sensitive. Your command is interpreted by the shell as having to run two separate commands

    n=  cat $a | wc -l
    #^^ ^^^^^^^^^^^^^^
    #1         2
    

    The first part just stores an empty string to the variable n and the next prints the line count of the file stored in variable a. Notice that the shell does not throw errors for this. Because it is not violating the syntax (just the semantics are wrong). But the line count is never assigned to the variable n.

    The error is seen when the conditional if [ $n -eq 0 ] is hit when you are doing a comparison with an empty variable on the LHS.

    You wanted to run a command and store its output, you need command-substitution($(..)) for that. Assuming the $a contains a name of a file just do

    n=$(wc -l < "$a")
    

    Note, that I've removed the useless cat usage and piping it to wc. But wc can read from an input stream directly.

    Also note that you have multiple bad practices in your script. Remember to do the following

    1. Always double-quote the shell variables - "$#", "$@", [ -f "$a" ], [ -d "$a" ]
    2. Don't use the `` for command-substitution, because it is not easily nestable and you might have issues related to quoting also.
    3. You can use conditional expression [[ if you are sure if the script is running under bash in which a variable containing spaces can be used without quoting on the LHS