Help sending mail through subshell

Hey I have a shell script that is like this:

(
 echo "hi!"
##DO SOMETHING
)&(
sleep 5
##EMAIL RECIPIENTS VARs
ERECIPIENT3="email.com"
echo "Connection on status: is Down"|mail -s "Subject:" ${ERECIPIENT3}
kill -- -$$
)

This isn't working anyone know why? mail won't go out from subshell 2, however in subshell 1 I can send mail for any alerts.

Thanks!

I'm not sure what you're even trying to do here.

What is the thing you're putting in background? What are you trying to do with it?

Why put the second thing in a subshell at all?

What is the & for? Are you trying to run a subshell in the background, wait for it, then kill it?

Hey Corona688,

in the first subshell I have a query on a database which is waiting on a correct response, if database is slow then
the simultaneous subshell running will have commands sleep and kill -$$ and send an email to me as an alert DB is going slowly!

Thanks. Let me know what your thoughts are.

---------- Post updated at 06:24 PM ---------- Previous update was at 06:14 PM ----------

Hey a more simple code sample is:

(
echo "hi"
)&(
sleep 5
##EMAILRECIPEIENTS INITIALIZE##
ERECIPIENT3="EMAILHERE"
Echo "connection slow"|mail -s "Subject:" {ERECIPIENT3}
kill -- -$$
)

(
        echo "Hi!"
        # Slow thing ) &

PID="$!"

for X in 1 2 3 4 5
do
        ps "$PID" >/dev/null 2>/dev/null || break
        sleep 1
done

if ps "$PID" >/dev/null 2>/dev/null
then
        # database query hasn't finished in 5 seconds
        kill "$PID"
fi
1 Like

If your OS has the /proc filesystem, you can use [ -d "/proc/$PID" ] instead of ps "$PID" >/dev/null 2>/dev/null

Guys,
I will attempt your ideas today before eofday.

I however have probably not explained this properly:

I understand two subshells or 1 subshell and main command going same time.

BUT, I need to add a mail function in both.
what I am attempting is that: If the sleep 5 in subshell gets to end and the subshell its in kills -- -$$ ALL before my other main or simultaneous shell is doing some intensive/timeconsuming calculation against a SQL DATABASE -- Then Send and alert mail-s

I just need probably help getting errors directed taking everything into account in a mail command rather then how to terminate both shells.

So basically my logic is:

()
&
()
----
Shell1-
(do intensive calculations and
initialize variables for mail alert
Send mail
kill -- -$$
)
subShell2
(Sleep 5-10 depend
send mail alert if
finishes sleep saying something like (HEY WATCHOUT DATABASE SLOW, OR CRASHED!)

kill -- -$$
)

can someone elaborate how I can remove all possible errors from a mail -s function and ignore them cause in my tests yesterday I noted that thats where the hanging up is occurring, mail -s ONLY, the logic I think might be alright unless im missing something.

Again: if anyone knows how to dev/null mail properly can you add it to a simple echo blah/sleep5/sendmail/kill -- -$$ everything good while other subshell goes with (a sleep -faster time then 1st shell/ alert mail/and kill -- -$$ with other subshell

I can get one subshell to mail alerts by switching sleep times around but other wont.

Thus in the grand scheme of things,
-if my db is slow at responding -and sending an email with the variables I get from DB -and kill before other shell
-the other subshell will -sleep on side and after send mail and then kill all

Thanks Guys!

Again, I'm not sure what 'kill -- -$$' is even trying to do. -- is not a valid option for kill, and killing your own shell would kill everything, leaving it not able to do anything. And -(number) would tell kill it's some strange kind of signal, not a process ID.

This is different from our suggestions how? Wait up to 5 seconds then kill, and if it had to be killed, email?

Once again, this logic doesn't make sense. & on a line by itself is meaningless, and -- why bother making a second subshell? You already have two shells, and you never background the second one anyway.

Oh, I see -- you are trying to launch two scripts simultaneously. Each will kill the other if it finishes first.

This doesn't seem a good way to solve the problem, really. That's the very definition of "race condition". Even assuming good conditions, who can say whether one will kill the other in time? Who can say whether they will die cleanly?

And there's no point! It's an over-complicated, extra-wasteful, extra-sloppy, extra-error-prone version of the exact same algorithm: "Wait up to x seconds, then kill and send email".

If you're trying to avoid some sort of problem with this convoluted method, it'd be nice to know what problem, so that we can show you how to actually avoid it.

I don't know what you're even trying to say here.

I will make my solution more complete in the hope you will actually try it:

#!/bin/bash

(
        echo "Hi!"

        # Using 'exec' means less mess if something goes wrong,
        # since the subshell is replaced wholly by it.
        exec sleep 1000
# Less stderr noise if you use 'disown'.
# If your shell doesn't have disown, it doesn't need it.
) & disown

PID="$!"        # The PID of the background process

MAXTIME=5
X=0 ; while [ "$X" -lt "$MAXTIME" ]
do
        let X=X+1
        # If the process is done, quit immediately
        ps "$PID" 2>&1 >/dev/null || exit

        echo "$X seconds, $PID still exists" >&2
        sleep 1
done

# The query hasn't finished in 5 seconds, so kill it.
kill "$PID" >/dev/null 2>&1 || exit

ERECIPIENT3="email.com"
# echo "Connection on status: is Down"|mail -s "Subject:" "${ERECIPIENT3}" >/dev/null 2>/dev/null

sleep 1 # Wait a second for it to die

# Kill it with a more severe signal and exit if it doesn't exist
kill -QUIT "$PID" >/dev/null 2>&1 || exit
sleep 1
# Try and kill it again with an unblockable signal, quit if it doesn't exist
kill -9 "$PID" # Last resort
exit

If 'mail' is hanging, it might be a good idea to find out why.

1 Like

hey Corona, thanks for the detailed help.
So basically I am trying out your script however I have a question about $! 's- functionality.

does it pick from within the script the most recent shell script or does it grab from all running scripts.
I am wonderring cause the documentation on it is confusing me. and the way we schedule linux scripts we have many running simultaneously and any clarification you can give me on $! would help clear my worries about it. - I am still googling

but does it grab from the entire history linux processes running at the time or will it only grab from within the script.

I will post my final script later so you guys can look and see what I was trying in the first place.

and FYI- the reason I am seperating the DB-connections is that the system hangs on lets say the first variable assignment which is a query from the DB.

--Your solution seems to cover it so thanks, -will be testing it for a day or so to see it on my dev environment. -I will proably use once I understand the scope of $!

Thanks.

---------- Post updated at 10:50 AM ---------- Previous update was at 10:30 AM ----------

I understand $! grabs from inside script can someone confirm??

$! is the process ID of whatever you backgrounded (i.e, ran with &) most recently inside the current shell.

So if you did ( .... ) & you would get the process ID of the subshell.

If you did sleep 1000 & you would get the process ID of sleep without any subshell involved at all.

etc.

BASH also has another meaning for "!", which relates to the shell history -- but, like aliases, this does not happen inside a shell script, only in live interactive terminal sessions.

1 Like

CORONA DUDE I LOVE YOU MAN. THE SCRIPT WORKS BEAUTIFULLY!

---------- Post updated at 11:45 AM ---------- Previous update was at 11:44 AM ----------

I will update you guys on my final deployment BUT TESTS WERE ALL GOOD :smiley:

1 Like

You might want to comment out the echo inside that loop before deploying. I'm not sure where all those debug statements will end up, if anywhere. Don't want them piling up in some neglected logfile :slight_smile:

1 Like

Will do and thanks for the heads up!
is there a any logs in specific your thinking of? i'm just curious.
what causes the pileup ? termination of the script ?

I removed the echos.

I don't know, that depends on what's running it. That's why any programs you write should make as little noise as possible unless they actually have anything important to say.

If it's run by an init script, it might end up somewhere in /var/log.

If it's run by cron, any program output from that gets automatically emailed to user@hostname via the server's own MTA... or dumped in $HOME/dead.letter if none's available. (Meaning, if it is cron-ed, it might be possible to simplify that script by letting cron do the mailing for it.)

etc.

It might go nowhere at all. It's not THAT big a deal in the end. I just don't want you to end up with a slowly growing file under /var/log which will get ignored for 10 years until the partitions full... Or a confused customer wondering why they're suddenly getting 3 emails full of nonsense a day :smiley: