I'm trying to debug my application on Mac OS X Mountain Lion using a bash script which is used to open the application with several input methods. Though I would like to the script to quit running with a short description what happened, if it encounters any error signals (without set -e).
Script is constructed in a following manner:
#!/bin/bash
#
...
while true
do
for input in $INPUTS
do
/path/to/app $input 2> mylog.log &
sleep 2
tail -2 /private/var/log/system.log | grep $ERROR &&
echo $input &&
exit 1;
test $? -gt 127 &&
echo $input &&
exit 2;
# nothing happened, kill the app and continue with a new test
pkill -9 app
done
done
And I've tried to debug the script by manually sending
pkill -SIGSEGV app
in Terminal.
I'm trying to get the script to print the output to the command line (hence the '&' in the app command) and also to the log file (2>), but it looks like if a crash occurred, it doesn't print the application log properly neither to the file nor terminal and the script just keeps running. Also, somehow the grep from system.log does not catch the crashes.
What would be a better option to monitor and catch application crashes in a shell script on Mac? I've done similar tests on Linux and they worked fine.
EDIT: I am also open for suggestions on other methods for monitoring crashes than a shell script. :-)
Related
I want a script to check if it has been started from within a terminal window. If it was started without window, it shall re-run itself in a visible terminal window.
If found this script line:
tty -s; if [ $? -ne 0 ]; then konsole -e "$0"; exit; fi
It works fine. However since it uses konsole, it is specific to KDE. Is there a more portable solution that runs on Linux system without KDE as well?
No generic solution exists that will work over ALL window systems. however, you can look into implementing a list of common terminal programs. Good thing all take '-e'.
if [ ... ] ; then
for t in konsole gnome-terminal xterm ; do
if type "$t" >/dev/null 2>&1 ; then
$t -e "$#"
break
fi
done
Also note that 'tty -s' checks if your current stdin is connected to a terminal. You probably want to add a test for valid display ("$DISPLAY"). No point in launching a terminal window, if not running under some window manager.
You can improve code further by checking for environment variables that let you know if you are running under terminal: 'GNOME_TERMINAL_SCREEN', 'XTERM_SHELL', or checking of '$TERM' for 'xterm*'.
I have a bash script, and I want to be able to keep a log in an xterm, and be able to send echo to it anytime.
How would I do this?
Check the GPG_TTY variable in your xterm session. It should have the value similar to
GPG_TTY=/dev/pts/2
This method should be available for terminals that support GNU Pinentry.
Another option to determine the current terminal name is to use
readlink /proc/self/fd/0
The last method applies only to Linux
Now if your bash script implements a command
echo "Hello, world!" > /dev/pts/2
This line should appear on the xterm screen.
I managed to make a console by running an xterm with a while loop clearing the screen, reading the contents of the log file, pauseing for a second, then looping again. Here was the command:
xterm -T Console -e "while true: do cls && cat ${0}-LOG.txt && sleep 1; done"
Then to send something to the console:
echo -e "\e[91;1mTest" >> ${0}-LOG.txt
And the console will update each second.
I am creating an application installer for Mac. The installer involves getting a code from the user on install. I used an Installer Plugin for the Code Input screen.
I have read (from this link) and verified that plugins do not work in the command line and Apple Remote Desktop. I can check if the installer is running from the command line using a variable ("$COMMAND_LINE_INSTALL").
My questions is, how can I programmatically check if it is running via Apple Remote Desktop?
If pstree is available, you can get a quick ancestry of the current process and see if Apple Remote Desktop is in it, something like pstree -p $$ in bash. Unfortunately, I installed pstree using brew, so this is most likely not going to be available for you, unless you distribute a binary yourself.
The other approach is to walk up the parent yourself. Here is a sample that I tested to be working to check if I am running inside iTerm (I used iTerm as a sample because I don't know what the pstree output would look like when running inside Apple Remote Desktop).
pid=$$
running_in_iterm=0
while [ $pid -ne 1 ]; do
command=$(ps -o command= -p $pid)
case "$command" in
*iTerm*)
running_in_iterm=1
break;;
esac
pid=$(ps -o ppid= -p $pid)
done
if [ $running_in_iterm -eq 1 ]; then
echo "Running in iTerm"
else
echo "Not running in iTerm"
fi
You can try running this script from both the built-in Terminal app as well as iTerm and see the difference.
I have a java program that stops often due to errors which is logged in a .log file. What can be a simple shell script to detect a particular text in the last/latest line say
[INFO] Stream closed
and then run the following command
java -jar xyz.jar
This should keep on happening forever(possibly after every two minutes or so) because xyz.jar writes the log file.
The text stream closed can arrive a lot of times in the log file. I just want it to take an action when it comes in the last line.
How about
while [[ true ]];
do
sleep 120
tail -1 logfile | grep -q "[INFO] Stream Closed"
if [[ $? -eq 1 ]]
then
java -jar xyz.jar &
fi
done
There may be condition where the tailed last log "Stream Closed" is not the real last log and the process is still logging the messages. We can avoid this condition by checking if the process is alive or not. If the process exited and the last log is "Stream Closed" then we need to restart the application.
#!/bin/bash
java -jar xyz.jar &
PID=$1
while [ true ]
do
tail -1 logfile | grep -q "Stream Closed" && kill -0 $PID && sleep 20 && continue
java -jar xyz.jar &
PID=$1
done
I would prefer checking whether the corresponding process is still running and restart the program on that event. There might be other errors that cause the process to stop. You can use a cronjob to periodically (like every minute) perform such a check.
Also, you might want to improve your java code so that it does not crash that often (if you have access to the code).
i solved this using a watchdog script that checks directly (grep) if program(s) is(are) running. by calling watchdog every minute (from cron under ubuntu), i basically guarantee (programs and environment are VERY stable) that no program will stay offline for more than 59 seconds.
this script will check a list of programs using the name in an array and see if each one is running, and, in case not, start it.
#!/bin/bash
#
# watchdog
#
# Run as a cron job to keep an eye on what_to_monitor which should always
# be running. Restart what_to_monitor and send notification as needed.
#
# This needs to be run as root or a user that can start system services.
#
# Revisions: 0.1 (20100506), 0.2 (20100507)
# first prog to check
NAME[0]=soc_gt2
# 2nd
NAME[1]=soc_gt0
# 3rd, etc etc
NAME[2]=soc_gp00
# START=/usr/sbin/$NAME
NOTIFY=you#gmail.com
NOTIFYCC=you2#mail.com
GREP=/bin/grep
PS=/bin/ps
NOP=/bin/true
DATE=/bin/date
MAIL=/bin/mail
RM=/bin/rm
for nameTemp in "${NAME[#]}"; do
$PS -ef|$GREP -v grep|$GREP $nameTemp >/dev/null 2>&1
case "$?" in
0)
# It is running in this case so we do nothing.
echo "$nameTemp is RUNNING OK. Relax."
$NOP
;;
1)
echo "$nameTemp is NOT RUNNING. Starting $nameTemp and sending notices."
START=/usr/sbin/$nameTemp
$START 2>&1 >/dev/null &
NOTICE=/tmp/watchdog.txt
echo "$NAME was not running and was started on `$DATE`" > $NOTICE
# $MAIL -n -s "watchdog notice" -c $NOTIFYCC $NOTIFY < $NOTICE
$RM -f $NOTICE
;;
esac
done
exit
i do not use the log verification, though you could easily incorporate that into your own version (just change grep for log check, for example).
if you run it from command line (or putty, if you are remotely connected), you will see what was working and what wasnt. have been using it for months now without a hiccup. just call it whenever you want to see what's working (regardless of it running under cron).
you could also place all your critical programs in one folder, do a directory list and check if every file in that folder has a program running under the same name. or read a txt file line by line, with every line correspoding to a program that is supposed to be running. etcetcetc
A good way is to use the awk command:
tail -f somelog.log | awk '/.*[INFO] Stream Closed.*/ { system("java -jar xyz.jar") }'
This continually monitors the log stream and when the regular expression matches its fires off whatever system command you have set, which is anything you would type into a shell.
If you really wanna be good you can put that line into a .sh file and run that .sh file from a process monitoring daemon like upstart to ensure that it never dies.
Nice and clean =D
I use Ubuntu and am trying to write a script that makes the following:
-test if an audio stream works
-if not, send an email.
I have tried the following code (running as a cron job every 10 minutes), which 'works' if I supply the wrong pw e.g.(it sends an email then), but does nothing if the actual server is down (tested by killing the server). any ideas on how to fix the script?
Thanks in advance!
#!/bin/bash
#servertest.sh
username=user1
password=xyz
url="http://wwww.streamingaudioserver.com -passwd $password -user $username"
mplayer $url &
sleep 5
test=$(pgrep -c mplayer)
if [ $test = 0 ]; then
#server is down!
mailfile="downmail.txt"
/usr/sbin/ssmtp test#maildomain.com < "/home/test/$mailfile"
fi
killall mplayer
sleep 5
exit
Your problem is in this line:
$mailfile="downmail.txt"
remove the dollar sign and that should do it.
You should be getting error messages in your cron log or emails to the crontab owner complaining about a command not found or no such file.
Edit:
Does your script work if run from the command line (with the stream down) rather than cron?
Try using set -x (or #!/bin/bash -x) in the script to turn on tracing or use echo "PID: $$, value of \$test: $test" > /tmp/script.out after the assignment to see if you're getting the zero you're expecting.
Also, try an ssmtp command outside the if to make sure it's working (but I think you already said it is under some circumstances).
Try your script without ever starting mplayer.