linuxshellunixawkgrep

Can I grep multiple AND arguments in if else?


I'm trying to grep multiple arguments in shell. I put orders like ./script arg1 arg2.. argN And I want them to act egrep -i "arg1" mydata | egrep -i "arg2" | ... egrep -i "argN" | awk -f display.awk in order to match patterns in AND format. What's wrong in my process?

Is it even right to code like egrep -i "arg1" mydata | egrep -i "arg2" | ... egrep -i "argN" | awk -f display.awk to get multiple patterns in AND format??

if [ $# -eq 0 ]
then
    echo "Usage:phone searchfor [...searchfor]"
    echo "(You didn't tell me what you want to search for.)"
    exit 0
else
    for arg in $*
    do
    if [ $arg -eq $1 ]
    then
            egrep -i "arg" mydata |
    else
            egrep -i "arg" |
    fi
    done
    awk -f display.awk     
fi

If my data has 'happy sunny bunny', 'sleepy bunny', and 'happy sunny'

I want them to perform if I tried ./script happy sunny bunny then only 'happy sunny bunny' comes out.

and if i tried ./script bunny then 'happy sunny bunny' 'sleepy bunny' both coming out.


Solution

  • The immediate fix is to move the pipe character to after the done.

    Also, you should loop over "$@" to preserve the quoting of your arguments, and generally quote your variables.

    if [ $# -eq 0 ]
    then
        # print diagnostics to stderr
        echo "Usage: phone searchfor [...searchfor]" >&2
        echo "(You didn't tell me what you want to search for.)" >&2
        exit 0
    fi
    for arg in "$@"
    do
        # Add missing dash before eq
        if [ "$arg " -eq "$1" ]
        then
            # Surely you want "$arg" here, not the static string "arg"?
            grep -E -i "$arg" mydata
        else
            grep -E -i "$arg"
        fi
    done |
    awk -f display.awk     
    

    The overall logic still seems flawed; you will be grepping standard input for the first argument if there are more than two arguments. Perhaps you want to add an option to allow the user to specify an input file name, with - to specify standard input? And then all the regular arguments will be search strings, like the usage message suggests.

    If indeed the intent is to loop over all the arguments to produce a logical AND, try this:

    also () {
        local what
        what=$1
        shift
        if [ $# -gt 0 ]; then
            grep -E -i "$what" | also "$@"
        else
            grep -E -i "$what"
        fi
    }
    
    also "$@" <mydata | awk -f display.awk
    

    ... though a better implementation might be to build a simple Awk or sed script from the arguments:

    script='1'
    for arg in "$@"; do
        script="$script && tolower(\$0) ~ tolower(\"$arg\")"
    done
    awk "$script" | awk -f display.awk
    

    This breaks down if the search phrases could contain regex specials, though (which of course is true for the grep -E version as well; but then you could easily switch to grep -F).

    Merging the two Awk scripts into one should probably not be hard either, though without seeing display.awk, this is speculative.