-2

I need to write a while loop in bash script that does exit when the process is ended successfully what I have tried so far is;

VAR=`ps -ef |grep -i tail* |grep -v grep |wc -l`
while true; do
{
if [ $VAR = 0 ]
then
echo "Sending MAils ...."
exit
fi
}
done
  • You set `VAR` before entering the loop, and you never change it afterwards. This means that either the condition `[ $VAR = 0 ]` is met on the first iteration, and the script exits immediately, or the condition is not met, and the loop runs forever. – user1934428 Jan 12 '23 at 12:08
  • Add any information that can help, like what `tail` commands you are running and the output of `ps -ef |grep -i tail* |grep -v grep`. – Walter A Jan 12 '23 at 13:26

2 Answers2

0

use break instead of exit to continue the execution of your script.

Also, there is no need for {.

akathimi
  • 1,393
  • 11
0

Your script has numerous errors. Probably try https://shellcheck.net/ before asking for human assistance.

You need to update the value of the variable inside the loop.

You seem to be reinventing pgrep, poorly.

(The regular expression tail* looks for tai, tail, taill, tailll ... What do you actually hope this should do?)

To break out of a loop and continue outside, use break.

The braces around your loop are superfluous. This is shell script, not C or Perl.

You are probably looking for something like

while true; do
   if ! pgrep tail; then
      echo "Sending mails ...."
      break
   fi
done

This avoids the use of a variable entirely; if you do need a variable, don't use upper case for your private variables.


Based on information in comments, if you have a number of processes like

tail -2000f /var/log/log.{1..10}

and no way to check their PIDs any longer, you might want to use fuser to tell you when none of them are running any longer:

while true; do
    fuser /var/log/log.{1..10} || break
    sleep 60
done
echo All processes are gone now.

Unfortunately, fuser does not reliably set its exit code - test on the command line (run tail -f $HOME/.bash_profile in one window and then fuser $HOME/.bash_profile && echo yes in another; then quit the tail and run fuser again. If it still prints yes you need something more.)

On MacOS, I found that fuser -u will print parentheses when the files are still open, and not when not:

while true; do
    fuser -u /var/log/log.{1..10} 2>&1 | grep -q '[()]' || break
    sleep 60
done

On Debian, fuser is in the package psmisc, and does set its exit code properly. You will probably also want to use the -s option to make it run quietly.

Notice also the addition of a sleep to avoid checking hundreds or thousands of times per second. You would probably want to make the same change to the original solution. How long to wait between iterations depends on how urgently you need the notification, and how heavy the operation to check the condition is. Even sleep 0.1 would be a significant improvement over the sleepless spin lock.

tripleee
  • 175,061
  • 34
  • 275
  • 318
  • The issue is I have multi "tail -2000f /var/log/log.{1..10}" that are running in the background and I want to wait untill they ended regardless how. and eventually this command "VAR=`ps -ef |grep -i tail* |grep -v grep |wc -l`" will return 0 which means all process's that start with tail are ended and I want to set a loop until this condition is met. How can I do It? – MohammedNour Al-Rawabdeh Jan 12 '23 at 11:26
  • If this answer doesn't work. it's probably because you have other unrelated `tail` processes running. Probably a better solution is to check with `fuser` whether some process is holding an open file handle to the log files. – tripleee Jan 12 '23 at 11:31
  • The `-f` option tells `tail` to never end, so what are you hoping for? And running tail on the background 10 times? Where will `tail` write it's output? – Walter A Jan 12 '23 at 13:24
  • I updated the answer to show a sketch of a `fuser` solution. – tripleee Jan 13 '23 at 11:51