looping curl and grep to query an API and process result all in one action - bash

Initially I was having trouble piping a curl and grep command because I was getting the same exit code if the server was down as I was for if the pattern was not found and that wasn't good. Here are some examples of solutions I was given for that:
#!/bin/bash
if curl http://192.168.1.2/api/query | grep -q mypattern; then
echo "Found pattern"
elif [ "${PIPESTATUS[0]}" -eq 0 ]; then
echo "Server up"
else
echo "Server down"
fi
Here is the other one:
if while ! curl http://192.168.1.2:8080/api/query; do sleep 1; done |
grep -q mypattern; then
echo "success"
fi
Now I am stuck again and trying to adapt them. Right now it will retrieve the contents of the queue. If it can't reach the server, it keeps trying until is does reach it. It will then process the queue to find the pattern. But I need to confirm the server is reachable AND process the queue all in one action. If EITHER the server is unreachable or the pattern is found, keep trying until the server responds AND the pattern is not found in the queue. After that, then I will do whatever. I am having trouble trying to come up with an efficient solution.

You can pipe the standard output of the entire while loop (which includes the output of the curl command) to another loop that runs until it finds your pattern in its input:
while ! curl http://...; do
# Write to standard error so that it isn't sent to grep
echo "Server down, waiting one second" >&2
sleep 1
done |
until grep -q mypattern; do
echo "Waiting for pattern to match"
done

Related

jenkins stuck after restarting remote service agent

This is part of bigger code that checking the OS version and choosing the correct condition by it.
( after checking OS version, it will go to this if condition: )
if [ "$AK" = "$OS6" ]
then
if [ "$(ls -la /etc/init.d/discagent 2>/dev/null | wc -l)" == 1 ]
then
/etc/init.d/discagent restart 2>&1 > /dev/null
/etc/init.d/discagent status |& grep -qe 'running'
if [ $? -eq 0 ] ; then
echo " Done "
else
echo " Error "
fi
fi
fi
If im hashing service discagent restart the pipeline is passing.
But if im not hashing it then it hang and not given any errors, And on the output file it is showing only the second server (out of few) that its hang on, And not moving to the next server.
what could be the issue?
p. S
while running it direct on the server it is working.
Run this script manually on the servers, that this script will be running on.
You can use xtrace -x which would show each statement before being executed, when you use with -v with -x so this would be -xv and the statement would be outputted, and then the line after the output of the statement with the variables substituted before the code is substituted.
using -u would show you the exact error when this occurs.
Another command is the trap command to debug your bash script.
More information on the following webpage,
https://linuxconfig.org/how-to-debug-bash-scripts

Bash loop, two conditions, first must be true and part of the loop

I'm migrating a bunch of openvz containers and can only do one at a time for reasons. This is very time consuming and if I'm not watching the destination node constantly I won't know if the migrations fail or are done.
So I'm trying to write a little shell script to do two things. First, make sure the container ID that is being migrated shows up in the list of containers. If it does not, exit the script and send me an email. Second, as long as the first condition is true, watch for the status of the container to change to running and once that is true send me an email.
I have the second part of this working using until, I'm not sure that is the best way to go about it though and I need the first part, making sure the container exists to work as well. Obviously both these tests need to run every loop in case the migration fails. I just can't wrap my head around how to do this.
Here is what I have so far:
#!/bin/bash
read -p "Container ID: " -e CID
until vzlist -a | grep $CID | grep running
do
sleep 600
done
echo "Migration of container $CID complete" | mail -s "Migration complete" red#cted.com
If I'm understanding how to interpret vxlist -a correctly, something like this should work:
#!/bin/bash
emailTarget="red#cted.com"
read -p "Container ID: " -e CID
while true; do # This loops until something `break`s it out of the loop
# Capture the container status, so we can run multiple checks with
# only one run of `vzlist`.
containerStatus=$(vzlist -a | grep "$CID")
if [[ -z "$containerStatus" ]]; then
# If the the result was the empty string, our container is not
# in the list, so apparently it's failed.
echo "Migration of container $CID failed" | mail -s "Migration failed" "$emailTarget"
break
elif [[ "$containerStatus" = *"running"* ]]; then
# It's in the list *and* has "running" status -- migration succeeded!
echo "Migration of container $CID complete" | mail -s "Migration complete" "$emailTarget"
break
fi
# If neither of those conditions was met, it's still trying;
# wait 10 minutes and check again.
sleep 600
done

Unable to exit line in bash script

I am writing a script to start an application, grep for the word "server startup", exit and then execute the next command. But it would not exit and execute next cmd after condition is met. Any help?
#!/bin/bash
application start; tail -f /application/log/file/name | \
while read line ; do
echo "$line" | grep "Server startup"
if [ $? = 0 ]
then
echo "application started...!"
fi
done
Don't Use Tail's Follow Flag
Tail's follow flag (e.g. -f) will not exit, and will continue to follow the file until it receives an appropriate signal or encounters an error condition. You will need to find a different approach to tracking data at the end of your file, such as watch, logwatch, or periodic log rotation using logrotate. The best tool to use will depend a lot on the format and frequency of your log data.

egrep is returning 0 in bash script but executing manually the command returning correct value | unix bash

I'm executing a bash script that returns me if ftp connection failed or was success using egrep, the issue is that when I'm trying to get a word with egrep is returning 0 but If I execute the command manually is returning 2.
this is my code:
#Create the FTP Connection.
for ip_address in ${IP_ADDRESS[#]}; do
ftp ${ip_address} <<ftp_commands > ${FTP_RESULTS}
user "${USER_ID}" "${USER_PASSWORD}"
pwd
bye
ftp_commands
ftp_result_id=`egrep -c "Login failed|Connection refused|Not connected|Connection timed out" ${FTP_RESULTS}`
if [ ${ftp_result_id} -gt 0 ]; then
echo "$(date +%m/%d/%y_%H:%M:%S) - ${ip_address} - Not connected" >> ${CONNECTION_RESULTS_FILE}
else
echo "$(date +%m/%d/%y_%H:%M:%S) - ${ip_address} - Connected" >> ${CONNECTION_RESULTS_FILE}
fi
done
the ftp_results_id is returning 0 in the egrep -c command, but I'm executing manually after it ran and create the file "FTP_RESULTS" and is working, it suppose that found 2 matches with "Not connected"
any suggestion?
The egrep -c command counts the matches.
Then you use a condition to do something if there are more than 0 matches.
A simpler and better solution is to use the exit code of egrep.
egrep exits with 0 (= success) if it found a match,
and non-zero otherwise.
You can write the if statement like this:
if egrep -q "Login failed|Connection refused|Not connected|Connection timed out" "${FTP_RESULTS}"; then
This is equivalent to the logic in your posted code.
There's no need for the ftp_result_id variable.
And there's no need to save the output of egrep.
I added the -q flag so that egrep doesn't produce any output.
None needed.

How to wait till a particular line appears in a file

Is it possible to write a script that does not proceed till a given line appears in a particular file?
For example I want to do something like this:
CANARY_LINE='Server started'
FILE='/var/logs/deployment.log'
echo 'Waiting for server to start'
.... watch $FILE for $CANARY_LINE ...
echo 'Server started'
Basically, a shell script that watches a file for line (or regex).
tail -n0 -f path_to_my_log_file.log | sed '/particular_line/ q'
You can use the q flag while parsing the input via sed. Then sed will interrupt tail as soon as Server started appears in /var/logs/deployment.log.
tail -f /var/logs/deployment.log | sed '/Server started/ q'
Another way to do the same thing
( tail -f -n0 /var/logs/deployment.log & ) | grep -q "Server Started"
Previous answer (works but not as efficient than this one)
We have to be careful with loops.
For example if you want to check for a file to start an algorithm you've probably have to do something like that:
FILE_TO_CHECK="/var/logs/deployment.log"
LINE_TO_CONTAIN="Server started"
SLEEP_TIME=10
while [ $(cat FILE_TO_CHECK | grep "${LINE_TO_CONTAIN}") ]
do
sleep ${SLEEP_TIME}
done
# Start your algorithm here
But, in order to prevent an infinite loop you should add some bound:
FILE_TO_CHECK="/var/logs/deployment.log"
LINE_TO_CONTAIN="Server started"
SLEEP_TIME=10
COUNT=0
MAX=10
while [ $(cat FILE_TO_CHECK | grep "${LINE_TO_CONTAIN}") -a ${COUNT} -lt ${MAX} ]
do
sleep ${SLEEP_TIME}
COUNT=$(($COUNT + 1))
done
if [ ! $(cat FILE_TO_CHECK | grep "${LINE_TO_CONTAIN}") ]
then
echo "Let's go, the file is containing what we want"
# Start your algorithm here
else
echo "Timed out"
exit 10
fi
CANARY_LINE='Server started'
FILE='/var/logs/deployment.log'
echo 'Waiting for server to start'
grep -q $CANARY_LINE <(tail -f $FILE)
echo 'Server started'
Source: adapted from How to wait for message to appear in log in shell
Try this:
#!/bin/bash
canary_line='Server started'
file='/var/logs/deployment.log'
echo 'Waiting for server to start'
until grep -q "${canary_line}" "${file}"
do
sleep 1s
done
echo 'Server started'
Adjust sleep's parameter to your taste.
If the line in the file needs to match exactly, i.e. the whole line, change grep's second parameter to "^${canary_line}$".
If the line contains any characters that grep thinks are special, you're going to have to solve that... somehow.

Resources