Exit to while read

Hi expert,

How do i exit to while read, below is the script.
I need to exit after execute echo or command.

or any scripts that can search two patterns and if they found any patterns execute the command and exit.

Thanks a lot..

tail -fn0 /tmp/test.log | \
while read line ; do
        echo "$line" | grep -q "Pattern1"
        echo "$line" | grep -q "Pattern2"
    if [ "$line" == "Pattern1" ]
        then
        echo "Pattern1"
		exit
    elif [ "$line" == "Pattern2" ]
        then
        echo "Pattern2"
		exit
    fi
done

exit will exit the script (or shell), and break will exit the while-loop.

You can use grep -E or egrep to search for multiple patterns, using a pipe character to separate the terms, and use the grep return code to see if a match was made.

e.g.

echo ... | egrep "Pattern1|Pattern2"

Alternatively, you could say:

if [[ "$line" =~ Pattern1 ]]; then
  ...
  ...
elif [ ... ]; then
  ...
  ...
fi

You'll want to add some word boundaries to any search to prevent false positive results.

tried the break after my echo but the script not break right away, I need to trigger append the pattern again to the /tmp/test.log

To append what? $line?

If so, simply echo that, grepping what need, if required, and redirect that to the log file.

same issue,

tail -fn0 /tmp/test.log | \
while read line ; do
        echo "$line" | grep -q "Pattern1"
        echo "$line" | grep -q "Pattern2"
if [[ "$line" =~ "patern1" ]]; then
        echo "Pattern1"
		break
elif [[ "$line" =~ "pattern2" ]]; then
        echo "Pattern2"
		break
fi
done

what to achieve is:
creating to monitor /tmp/test.log if they found "pattern1" then execute the command and run the next line or next command or if they found "pattern2" then other command will executed

Well, if you want to monitor the log, it doesn't make much sense to exit (or break) at all.

tail -fn0 test.log | while read line; do
if [[ "$line" =~ "Pattern1" ]]; then
  # do something here
  echo $line >> test2.log
elif [ "$line" =~ "Pattern2" ]; then
  # do something else here
  echo $line >> test2.log
  fi
done

(ideally this is something you would likely run nohup in the background)

hi Scott,
here my script

func_monitoring () {
tail -fn0 /tmp/test.log | \
while read line ; do
        echo "$line" | grep -q "pattern1"
        echo "$line" | grep -q "pattern2"
    if [ "$line" == "pattern1" ]
        then
                echo "patter1"
                break
    elif [ "$line" == "pattern2" ]
        then
                echo "patter2"
                break
    fi
done
}

func_menu () {

while :
  do
clear
  echo ""
  echo ""
  echo "               [1] Monitor the log"
  echo ""
  echo "               [2] Exit"
  echo ""
  echo ""
  echo "        Select Number"
  echo ""
  echo -n "        Please Select [1-2]: "
  read yourch
  case $yourch in
   1)  func_monitoring ; read -n 1;;
   2)  clear ; exit 0
       ;;
    *) echo "       Please select choice 1 or 2"
       read -n 1
       ;;
  esac
done
}
func_menu

---------- Post updated at 11:52 AM ---------- Previous update was at 11:51 AM ----------

after found any pattern must be go back to the menu after 5s but is not happening

---------- Post updated at 11:56 AM ---------- Previous update was at 11:52 AM ----------

here's the scripts goes:
screen 1

  1. sh test.sh

               [1] Monitor the log

               [2] Exit


        Select Number

        Please Select [1-2]: 1

from screen 2
will execute this:
echo 'pattern1' >> /tmp/test.log

result
screen 1:


               [1] Monitor the log

               [2] Exit


        Select Number

        Please Select [1-2]: 1
patter1

is not go back to menu after echo the pattern, i need to go back to the main menu

---------- Post updated at 11:59 AM ---------- Previous update was at 11:56 AM ----------

---------- Post updated at 01:01 PM ---------- Previous update was at 11:59 AM ----------

Thanks scott,

Solved it by adding this:

		echo "        Please [Enter] key to continue..."
		ps aux |grep tail -m 1 |awk '{print "kill " $2}' |sh
                break

You haven't said what shell or operating system you're using. When I try the following script on a macBook Pro running macOS Sierra version 10.12.6 using ksh (version sh (AT&T Research) 93u+ 2012-08-01 ), I think it does what you want:

#!/bin/ksh
logfile=/tmp/test.log

func_monitoring() {
	printf '	Monitoring "%s"...\n' "$logfile"
	tail -f -n0 "$logfile" | 
	while read line
	do	printf '(func_monitoring read) %s\n' "$line"
		if [ "$line" = "pattern1" ]
		then	echo "patter1"
			return
		elif [ "$line" = "pattern2" ]
		then	echo "patter2"
			return
		fi
	done
}

func_menu() {
	while :
	do	clear
		printf "%s

			[1] Monitor the log

			[2] Exit


		Please Select Number [1-2]: " "$directions"

		directions=
		read -n1 yourch
		case $yourch in
		(1)	echo
			func_monitoring
			sleep 5;;
		(2)	clear
			echo Goodbye.
			exit 0;;
		(*)	directions='	Please select choice 1 or 2';;
		esac
	done
}
func_menu

it loops on the read in func_monitoring until a line is found that matches one of the two given strings. Then it prints a line and sleeps for 5 seconds. And then it returns to the menu display loop in func_menu .

When I try running the same code with bash (version GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin16) ) func_monitoring doesn't return to func_menu until it has read another line from your log file after finding a matching line (which I assume is why you're trying to kill the tail after finding a matching line).

1 Like

Wouldn't a case statement lend itself to evaluating the patterns in func_monitoring ?

Yes. Using case patterns to match lines instead of using test 's = operator would help if matching words on a line instead of looking for exact matches to a complete line is the desired goal.

But, making that change won't affect when tail terminates after the remainder of the pipeline terminates. For that we need to know what shell is being used and what version of that shell. I've shown a way to make it work with the Korn shell if I understand what lxdorney is trying to do correctly (and I'm not sure that I do). I believe that some versions of bash have an option to make the last process in a pipeline the process group leader of that pipeline (like ksh does) instead of the first process in the pipeline (like bash does by default), but I'm not going to try to research ways to do this in every possible shell when lxdorney could tell us what version of what shell is being used so we could reasonably limit our research.

OS: centos 6.9

Great. Now we know what operating system you're using.

But, since i neither use nor have access to a system that is running that OS, I still don't know what what shell is installed as /bin/sh on your system. What output do you get when you run the command sh --version ?

What output do you get when you run the command bash --version ? And, what output do you get when you run the command bash --lastpipe ?

Do you have ksh installed on your system? What output do you get from the command ksh --version ?

I provided a script in post #8 in this thread. Did you try installing it and executing it with ksh ? If so, what happened? If not, why not?

GNU bash, version 4.1.2(2)-release-(x86_64-redhat-linux-gnu)
Usage:  sh [GNU long option] [option] ...
        sh [GNU long option] [option] script-file ...
GNU long options:
        --debug
        --debugger
        --dump-po-strings
        --dump-strings
        --help
        --init-file
        --login
        --noediting
        --noprofile
        --norc
        --posix
        --protected
        --rcfile
        --rpm-requires
        --restricted
        --verbose
        --version
Shell options:
        -irsD or -c command or -O shopt_option          (invocation only)
        -abefhkmnptuvxBCHP or -o option
Type `sh -c "help set"' for more information about shell options.
Type `sh -c help' for more information about shell builtin commands.

---------- Post updated at 09:07 PM ---------- Previous update was at 09:02 PM ----------

I tried the script and execute this command to append the test.log

echo "pattern1" >>/tmp/test.log

but same is not go back to menu and when try to execute again the

echo "pattern2" >>/tmp/test.log

, then is back to the menu.

Sorry my apologies, 2 append with any patterns, "pattern1 or pattern2" is working, I will edit my reply