Searching for pattern in variable using case statements

i would like to search a variable for a pattern, without having make any calls to external tools.

i have a code like this:

COUNTPRO2="gine is very bad
vine is pretty good"

case "${COUNTPRO2}" in
*vine*)
    factor=${COUNTPRO2}
    echo $factor
;;
esac

If the variable contains a specific pattern, i.e. in this case "vine", then i want the case statement to output ONLY the line containing the pattern..i.e.

vine is pretty good

is this possible?

what i was doing before was:

factor=$(echo "${COUNTPRO2}" | egrep vine)

I would like to avoid calling the egrep.

the solution needs to be portable as i intend to use it on linux, aix and sunos

Hi.

It would probably be useful if you were to tell us which items the different platforms had in common: bash, ksh, zsh, awk, perl, grep , etc.

Here's a solution using an array, loop, and case:

#!/usr/bin/env bash

# @(#) s1       Demonstrate shell array with case selector.

# Utility functions: print-as-echo, print-line-with-visual-space, debug.
# export PATH="/usr/local/bin:/usr/bin:/bin"
LC_ALL=C ; LANG=C ; export LC_ALL LANG
pe() { for _i;do printf "%s" "$_i";done; printf "\n"; }
pl() { pe;pe "-----" ;pe "$*"; }
db() { : ; }
db() { ( printf " db, ";for _i;do printf "%s" "$_i";done;printf "\n" ) >&2 ; }
C=$HOME/bin/context && [ -f $C ] && $C

v1="gine is very bad
vine is pretty good"

pl " Input data variable, piped into cat:"
echo "$v1" | cat -n

pl " Input data array with printf:"
declare -a a1="$v1"
printf "%s\n" "${a1[*]}"

pl " Looking through each element in the array:"
IFS=$'\n'
for line in ${a1[*]}
do
  db " Working on line [$line]"
  case $line in
  (*vine*)      echo " HIT! Found vine." ;;
  esac
done

exit 0

producing:

$ ./s1

Environment: LC_ALL = C, LANG = C
(Versions displayed with local utility "version")
OS, ker|rel, machine: Linux, 3.16.0-4-amd64, x86_64
Distribution        : Debian 8.4 (jessie) 
bash GNU bash 4.3.30

-----
 Input data variable, piped into cat:
     1  gine is very bad
     2  vine is pretty good

-----
 Input data array with printf:
gine is very bad
vine is pretty good

-----
 Looking through each element in the array:
 db,  Working on line [gine is very bad]
 db,  Working on line [vine is pretty good]
 HIT! Found vine.

See man bash , etc. for details.

Best wishes ... cheers, drl

1 Like

they have awk in common.

What about a while loop?

COUNTPRO2="gine is very bad
vine is pretty good"

echo "${COUNTPRO2}" | while read line; do
        [[ $line == *"vine"* ]] && echo $line
done
1 Like

this seems to do precisely what i needed. not sure how much time it'll save as oppose to calling grep for each pattern i'm searching for.

It would all depend upon the number of lines the code is traversing.

You could also try:

#!/bin/ksh
COUNTPRO2="gine is very bad
vine is pretty good"

while IFS= read -r factor
do	case "$factor" in
	(*vine*)printf '%s\n' "$factor"
		;;
	esac
done <<EOF
$COUNTPRO2
EOF

Note that I used printf instead of echo because the output you get from echo might not be what you want if a line in the expansion of $COUNTPRO2 starts with a hyphen or contains any backslash characters. And, using a here-document instead of an array makes it portable to many more shells.

Forking and execing an external utility is a VERY slow operation when compared to the actions required to perform a case statement pattern match.

Although the above was written and tested using a Korn shell, this should work with any shell that is based on Bourne shell syntax (including a 1970's vintage pure Bourne shell).

2 Likes

Old Bourne shells do not like ( ) in a case selector, and no -r for read.

#!/bin/sh
COUNTPRO2="gine is very bad
vine is pretty good"

while IFS= read factor
do
    case "$factor" in
    *vine*)
        printf '%s\n' "$factor"
    ;;
    esac
done <<EOF
$COUNTPRO2
EOF

A here-document uses a /tmp file. Another method is a pipe to the while loop

#!/bin/sh
COUNTPRO2="gine is very bad
vine is pretty good"

printf '%s\n' "$COUNTPRO2" |
while IFS= read factor
do
    case "$factor" in
    *vine*)
        printf '%s\n' "$factor"
    ;;
    esac
done
1 Like