Check if a process is running with shell script - bash

I'm trying to make a script to see if the process chromium is running.
The script should check every 10 seconds if the process is running and it must end when it finds it 10 times.
Here is my code.
#!/bin/bash
count=0
while true; do
sleep 10s
isthere=`$(top) | grep -w chromium`
if [ $isthere -ne 0 ]; then
count=$((count+1))
fi
if [ $count -eq 10 ]; then
echo "You found the process 10 times"
exit 50
fi
done
I'm having no output whatsoever. I don't know if I'm using the command top properly.

Yep, your usage of top command is incorrect. You try to invoke it from the shell script and it hangs as a result.
You should use top command with some specific options. I suggest you use it with -b option which corresponds to the "batch" mode and -n options which is for the number of iterations top produces its output. For more information check man top.
Also the test for isthere variable should be amended (we check it for non-emptyness).
The resulting script which works is something like this:
#!/bin/bash
count=0
while true; do
sleep 10s
isthere=`top -b -n 1 | grep -w chromium`
if [ -n $isthere ]; then
count=$((count+1))
fi
if [ $count -eq 10 ]; then
echo "You found the process 10 times"
exit 50
fi
done

Please use pgrep.
$ if pgrep ksh >/dev/null; then echo "ksh is running"; fi
ksh is running
In a loop:
i=0
while (( i < 10 )); do
if pgrep ksh >/dev/null; then
(( ++i ))
fi
sleep 10
done
Substitute ksh with the tool of your choice.

Related

How can we make a TIMER with (RESET) functionality in bash

I am very new to shell scripting, I have googled many things for this problem. But cannot find a perfect solution to it.
Problem is: It's a log monitoring code with "ERROR", Pattern
How can we make a TIMER in unix scripting. Support I have a timer of 5 minutes, and time keep on decreasing every 1 second. So I want to reset again the timer to 5 minute on certain condition (say $FREQUENCY of ERROR occurrence is greater then say for ex2).
#!/usr/bin/env bash
PATTERN='ERROR'
TIMER=300
FREQUENCY=2
while true;
do grep -i $PATTERN logfile > tmp_log
while [ $TIMER -gt 0 ]
do
sleep 1 &
printf " $TIMER \r" &
TIMER=$[$TIMER-1];
wait
done
if [[ $(wc -l <tmp_log) -ge $FREQUENCY ]]
then
TIMER=300
echo $TIMER
fi
sleep $TIMER
done
#!/bin/bash
PATTERN='ERROR'
TIMER=300
FREQUENCY=2
while true
do
while [ $TIMER -gt 0 ]
do
sleep 1
TIMER=$((TIMER - 1))
grep -i $PATTERN logfile > tmp_log
count=`wc -l tmp_log | awk '{ print $1 }'`
if [ $count -gt $FREQUENCY ]
then
TIMER=300
fi
done
break
done
This is good going for your case.

How to read and run a command 10 lines at a time in bash?

I have a bash script that connects to servers via SSH to run a command. The script gets the IP address from a file.
Problem: if I have 500 IPs in the file, I don't want to simultaneously open or try to open 500 connections. I want to do, lets say, 10 at a time in order to save resources.
How do I run the command via SSH 10 servers at a time?
Here is my script:
#/bin/bash
nodes="big_list_of_nodes.txt"
while read node; do
# Running in background
(uptime=`ssh -o ConnectTimeout=5 $node uptime 2>&1`
if [ $? -eq 0 ]; then
echo "$node uptime: $uptime"
else
echo "Connection timeout for node $node"
fi) &
done < $nodes
# Wait for all jobs to finish
wait
You want to write a function to do all the work for you that takes an IP address as an argument. Then use parallel to read in the file and distribute work to the function:
function get_uptime()
{
node=$1
uptime=`ssh -o ConnectTimeout=5 $node uptime 2>&1`
if [ $? -eq 0 ]; then
echo "$node uptime: $uptime"
else
echo "Connection timeout for node $node"
fi
}
export -f get_uptime
parallel -j 10 --will-cite -a big_list_of_nodes.txt get_uptime
The -j argument tells parallel how many jobs can be active at a time.
I was able to figure it out and make it work.
I add N lines to an array, then I process everything in that array. Then the array is empty and the process is repeated.
This way, you can have a file with hundreds of hostnames or IP address and process in N chunks.
#/bin/bash
nodes=`cat big_list_of_nodes.txt`
for node in $nodes
do
array+=($node)
if [ ${#array[#]} -gt 10 ]; then
for n in ${array[#]}
do
(uptime=`ssh -o ConnectTimeout=5 $n uptime 2>&1`
if [ $? -eq 0 ]; then
echo "$n uptime: $uptime"
else
echo "Connection timeout for node $n"
fi) &
done
wait
array=()
fi
done
if [ ${#array[#]} -gt 0 ]; then
for n in ${array[#]}
do
(uptime=`ssh -o ConnectTimeout=5 $n uptime 2>&1`
if [ $? -eq 0 ]; then
echo "$n uptime: $uptime"
else
echo "Connection timeout for node $n"
fi) &
done
wait
fi

BASH Keep counter through reboots

I'm trying to keep a external counter in my bash script.
As most of the script is specific to what it's for, I'm only going to insert the pertinent parts that I can't seem to get working. Everything before does get defined. Also before someone comments about the cat, I tried (< $TMPFILE) as well. The issue appears to be not writing to the file.
#!/bin/bash
TMPFILE="/tmp/nettestnum"
if [ -e "$TMPFILE" ]; then I=$(cat $TMPFILE); else I="1"; fi
nettest_start() {
grep -q "/root/bin/nettest" /etc/rc.local
if [ $? -eq 1 ]; then
sed -i 's|touch /var/lock/subsys/local|touch /var/lock/subsys/local \&\& /root/bin/nettest|' /etc/rc.local 2>&-
echo "Script started at $DATEVAL" >> "$LOGFILE" 2>&1
echo "Script will run every $TIMELb minutes, $LIMIT times"
touch "$TMPFILE"
nettest_run
else
echo "Nettest is already started and will relaunch upon next reboot"
fi
}
nettest_run() {
echo "$DATE : Starting scan" >> "$LOGFILE" 2>&1
#
while [[ "$I" -lt "$LIMIT" ]]
do
echo "$DATE : Starting scan" >> "$LOGFILE" 2>&1
#
HOSTS="$(...)"
for myHost in $HOSTS
do
PING=$(ping -f -c $COUNT "$myHost" |grep 'rtt' | awk '{print $4}')
echo "$myHost / $PING" >> "$LOGFILE" 2>&1
done
echo "$DATEVAL : Finished" >> "$LOGFILE" 2>&1
echo "$DATEVAL : Netstat Start" >> "$STATLOG" 2>&1
netstat -s |egrep -i "dropped|loss|reject|timeout|invalid" >> "$STATLOG" 2>&1
echo "$DATEVAL : Netstat Finished" >> "$STATLOG"G 2>&1
echo "." >> "$LOGFILE" 2>&1
sleep "$TIMEL"
let I++ || true
set +C
echo "$I" > "$TMPFILE"
done
}
Edit 4: re-added } and showing both functions.
I also need to figure out how to write an exit for the loop, but I'm pretty sure that's just a [ $? = 0 ]
Edit:
An example of some of the output I'm seeing when I run a status command (built into the script)..
Nettest is enabled on startup
PID number: 6059
Nettest is actively running in memory
On iteration of 100
iteration shows 1 on the first run.
Edit 2: redid the sample with full example, minus customized commands.
In the end, I got it working by adding 2>&1 to the line needed.
echo "$I" > "$TMPFILE" 2>&1
Try this:
if [ -e "$TMPFILE" ]; then I=`cat $TMPFILE`; else I=1; fi
while [[ $I -lt $LIMIT ]]
A while loop creates a subshell, with a copy of all your current variables.
#!/bin/bash
I=1
CHECK=1 # boolean for demonstration
while CHECK; do
let I++
CHECK=0
done
echo $I # prints 1, not two
This happens because the while subshell gets a copy of the I variable, which it increments. Once the subshell exits, the original variable comes back.
Your I variable is being incremented, and acting as your loop counter. I expect this is causing you all kinds of problems for properly ending your loop, and having other bits of this program see the "right" variable. I see no reason you could not replace the while loop with an equivalent for loop, and avoid all of these problems entirely.

bash: running cURLs in parallel slower than one after another

We have to cache quite a big database of data after each upload, so we created a bash script that should handle it for us. The script should start 4 paralel curls to the site and once they're done, start the next one from the URL list we store in the file.
In theory everything works ok, and the concept works if we run the run 4 processes from our local machines to the target site.
If i set the MAX_NPROC=1 the curl takes as long as it would if the browser hits the URL
i.e. 20s
If I set the MAX_NPROC=2 the time request took, triples.
Am I missing something? Is that an apache setting that is slowing us down? or is this a secret cURL setting that I'm missing?
Any help will be appreciated. Please find the bash script below
#!/bin/bash
if [[ -z $2 ]]; then
MAX_NPROC=4 # default
else
MAX_NPROC=$2
fi
if [[ -z $1 ]]; then
echo "File with URLs is missing"
exit
fi;
NUM=0
QUEUE=""
DATA=""
URL=""
declare -a URL_ARRAY
declare -a TIME_ARRAY
ERROR_LOG=""
function queue {
QUEUE="$QUEUE $1"
NUM=$(($NUM+1))
}
function regeneratequeue {
OLDREQUEUE=$QUEUE
echo "OLDREQUEUE:$OLDREQUEUE"
QUEUE=""
NUM=0
for PID in $OLDREQUEUE
do
process_count=`ps ax | awk '{print $1 }' | grep -c "^${PID}$"`
if [ $process_count -eq 1 ] ; then
QUEUE="$QUEUE $PID"
NUM=$(($NUM+1))
fi
done
}
function checkqueue {
OLDCHQUEUE=$QUEUE
for PID in $OLDCHQUEUE
do
process_count=`ps ax | awk '{print $1 }' | grep -c "^${PID}$"`
if [ $process_count -eq 0 ] ; then
wait $PID
my_status=$?
if [[ $my_status -ne 0 ]]
then
echo "`date` $my_status ${URL_ARRAY[$PID]}" >> $ERROR_LOG
fi
current_time=`date +%s`
old_time=${TIME_ARRAY[$PID]}
time_difference=$(expr $current_time - $old_time)
echo "`date` ${URL_ARRAY[$PID]} END ($time_difference seconds)" >> $REVERSE_LOG
#unset TIME_ARRAY[$PID]
#unset URL_ARRAY[$PID]
regeneratequeue # at least one PID has finished
break
fi
done
}
REVERSE_LOG="$1.rvrs"
ERROR_LOG="$1.error"
echo "Cache STARTED at `date`" > $REVERSE_LOG
echo "" > ERROR_LOG
while read line; do
# create the command to be run
DATA="username=user#server.com&password=password"
URL=$line
CMD=$(curl --data "${DATA}" -s -o /dev/null --url "${URL}")
echo "Command: ${CMD}"
# Run the command
$CMD &
# Get PID for process
PID=$!
queue $PID;
URL_ARRAY[$PID]=$URL;
TIME_ARRAY[$PID]=`date +%s`
while [ $NUM -ge $MAX_NPROC ]; do
checkqueue
sleep 0.4
done
done < $1
echo "Cache FINISHED at `date`" >> $REVERSE_LOG
exit
The network is almost always the bottleneck. Spawning more connections usually makes it slower.
You can try to see if parallel'izing it will do you any good by spawning several
time curl ...... &

Bash loop ping successful

I'm thinking that this needs to be changed to a while clause, at the moment it'll wait till all 10000 pings are done, I need it to return when the ping is successful. The program "say" is on OSX it makes the computer speak.
#!/bin/bash
echo begin ping
if ping -c 100000 8.8.8.8 | grep timeout;
then echo `say timeout`;
else echo `say the internet is back up`;
fi
OK I don't have rights to answer my own question so here's my answer for it after playing around:
Thanks, yeah I didn't know about $? until now. Anyway now I've gone and made this. I like that yours doesn't go forever but in my situation I didn't need it to stop until it's finished.
#!/bin/bash
intertube=0
echo "begin ping"
while [ $intertube -ne 1 ]; do
ping -c 3 google.com
if [ $? -eq 0 ]; then
echo "ping success";
say success
intertube=1;
else
echo "fail ping"
fi
done
echo "fin script"
You probably shouldn't rely on textual output of a command to decide this, especially when the ping command gives you a perfectly good return value:
The ping utility returns an exit status of zero if at least one response was heard from the specified host; a status of two if the transmission was successful but no responses were received; or another value from <sysexits.h> if an error occurred.
In other words, use something like:
((count = 60)) # Maximum number to try.
while [[ $count -ne 0 ]] ; do
ping -c 1 8.8.8.8 # Try once.
rc=$?
if [[ $rc -eq 0 ]] ; then
((count = 1)) # If okay, flag loop exit.
else
sleep 1 # Minimise network storm.
fi
((count = count - 1)) # So we don't go forever.
done
if [[ $rc -eq 0 ]] ; then # Make final determination.
echo `say The internet is back up.`
else
echo `say Timeout.`
fi
You don't need to use echo or grep. You could do this:
ping -oc 100000 8.8.8.8 > /dev/null && say "up" || say "down"
This can also be done with a timeout:
# Ping until timeout or 1 successful packet
ping -w (timeout) -c 1
I use this Bash script to test the internet status every minute on OSX
#address=192.168.1.99 # forced bad address for testing/debugging
address=23.208.224.170 # www.cisco.com
internet=1 # default to internet is up
while true;
do
# %a Day of Week, textual
# %b Month, textual, abbreviated
# %d Day, numeric
# %r Timestamp AM/PM
echo -n $(date +"%a, %b %d, %r") "-- "
ping -c 1 ${address} > /tmp/ping.$
if [[ $? -ne 0 ]]; then
if [[ ${internet} -eq 1 ]]; then # edge trigger -- was up now down
echo -n $(say "Internet down") # OSX Text-to-Speech
echo -n "Internet DOWN"
else
echo -n "... still down"
fi
internet=0
else
if [[ ${internet} -eq 0 ]]; then # edge trigger -- was down now up
echo -n $(say "Internet back up") # OSX Text-To-Speech
fi
internet=1
fi
cat /tmp/ping.$ | head -2 | tail -1
sleep 60 ; # sleep 60 seconds =1 min
done
If you use the -o option, BSD ping (which is also on macOS) will exit after receiving one reply packet.
Further reading: https://www.freebsd.org/cgi/man.cgi?query=ping
EDIT: paxdiablo makes a very good point about using ping’s exit status to your advantage. I would do something like:
#!/usr/bin/env bash
echo 'Begin ping'
if ping -oc 100000 8.8.8.8 > /dev/null; then
echo $(say 'timeout')
else
echo $(say 'the Internet is back up')
fi
ping will send up to 100,000 packets and then exit with a failure status—unless it receives one reply packet, in which case it exits with a success status. The if will then execute the appropriate statement.
Here's my one-liner solution:
screen -S internet-check -d -m -- bash -c 'while ! ping -c 1 google.com; do echo -; done; echo Google responding to ping | mail -s internet-back my-email#example.com'
This runs an infinite ping in a new screen session until there is a response, at which point it sends an e-mail to my-email#example.com. Useful in the age of e-mail sent to phones.
(You might want to check that mail is configured correctly by just running echo test | mail -s test my-email#example.com first. Of course you can do whatever you want from done; onwards, sound a bell, start a web browser, use your imagination.)
I liked paxdiablo's script, but wanted a version that ran indefinitely. This version runs ping until a connection is established and then prints a message saying so.
echo "Testing..."
PING_CMD="ping -t 3 -c 1 google.com > /dev/null 2>&1"
eval $PING_CMD
if [[ $? -eq 0 ]]; then
echo "Already connected."
else
echo -n "Waiting for connection..."
while true; do
eval $PING_CMD
if [[ $? -eq 0 ]]; then
echo
echo Connected.
break
else
sleep 0.5
echo -n .
fi
done
fi
I also have a Gist of this script which I'll update with fixes and improvements as needed.

Resources