I am trying to tail a log file and check for server up condition, once the string matches, it should return the same O/P in the variable. - bash

The problem is that tail -f doesn't exits by itself and my script stalls.
I am using sleep 15 because after triggering the shutdown command string 'org.apache.coyote.AbstractProtocol' appears after 15 sec in logs. In this way tail -100 works and gives the desired result.
Below is the snippet of code which I have written and its working fine, but I want to check it dynamically by tail -f. Please guide me how can I do it by tail -f and exiting the tail by some way.
ALFRESCO_LOGS="$CATALINA_BASE/logs"
printf "Stopping alfresco instance.\n\n"
$CATALINA_HOME/bin/shutdown.sh &> /dev/null
sleep 15
CHECK_ALFRESCO_LOGS=$(tail -100 $ALFRESCO_LOGS/catalina.out | grep --line-buffered 'org.apache.coyote.AbstractProtocol' | awk 'NR==1{print $NF}')
echo "$CHECK_ALFRESCO_LOGS"
if [[ "$CHECK_ALFRESCO_LOGS" == "stop" ]];
then
echo "Alfresco instance has been stopped."
fi

If you're OK with tail -f receiving SIGPIPE, this is a straightforward way:
while read CHECK_ALFRESCO_LOGS; do
echo "$CHECK_ALFRESCO_LOGS"
if [[ "$CHECK_ALFRESCO_LOGS" == "stop" ]]; then
echo "Alfresco instance has been stopped."
break
fi
done < <( tail -f $ALFRESCO_LOGS/catalina.out | awk '/org.apache.coyote.AbstractProtocol/{print $NF}')
When the condition matches, the while loop ends. That closes the input redirection, and thus the tail process receives SIGPIPE, which closes it.

Related

How to run a script in the background then when a condition is met, return it to foreground BASH

I want to run a script in the background, and when the time comes bring it back from background and call another script that will take in user input from the command-line, when I use this code, it's able to run the script effectively, but when it calls the other script, it only prints out a couple lines and It isn't able to take in user input, just straight up exits out. Been at it for a couple hours, no idea what to do from here.
I call this script with ./runTool.sh &
currTime=$(ls -lu | grep test01 | awk '{print $8}')
currHour="${currTime:0:2}"
currMin="${currTime:3:3}"
check=0
while [ true ]
do
timestamp=$(ls -lu | grep test01 | awk '{print $8}')
timeHour="${timestamp:0:2}"
timeMin="${timestamp:3:3}"
if (( $timeHour > $currHour )) || (( $timeMin > $currMin )) || (($timeHour < $currHour ))
then
check=1
set -m
fg %1
./tool.sh
break
fi
sleep 1
done

How to 'grep' a continuous log file stream with 'tailf' and when the needed string is obtained, close/break the 'tailf' automatically?

into a bash script, I need to grep a contiuous log streaming and when the proper string is filtered, I need to stop the 'tailf' command to move ond with other implementations.
The common command that works is:
tailf /dir/dir/dir/server.log | grep --line-buffered "Started in"
after the "Started in" line is gathered, I need to break down the "tailf" command.
All this stuff into a bash script.
use grep -m1, it means return the first match then stop:
-m num, --max-count=num
Stop reading the file after num matches.
tailf /dir/dir/dir/server.log | grep -m1 "Started in"
Figured out...
tailf /dir/dir/dir/server.log | while read line
do
echo $line | grep "thing_to_grep"
if [ "$?" -eq "0" ]; then
echo "";echo "[ message ]";echo "";
kill -2 -$$
fi
done
$$ is the PID of the current shell, in this case associated to the "tailf" command.

Matching one line from continuous stream in Linux shell

How can I make the following commands exit immediately after the first line is matched? I understand that SIGPIPE is not sent to cat until it tries to write next time (tail bug report), but I don't understand how to solve this issue.
cat <( echo -ne "asdf1\nzxcv1\nasdf2\n"; sleep 5; echo -ne "zxcv2\nasdf3\n" ) | grep --line-buffered zxcv | head --lines=1
cat <( echo -ne "asdf1\nzxcv1\nasdf2\n"; sleep 5; echo -ne "zxcv2\nasdf3\n" ) | grep --max-count=1 zxcv
NB: I actually had tail --follow before the pipesign, but replaced it with catand sleep to simplify testing. The shell in question is GNU bash 4.4.12(1)-release, and I'm running MINGW that came with Git-for-Windows 2.12.2.2.
CLARIFICATION: I have a jboss server which is started in a docker container and which outputs couple thousand lines of text within three minutes to a log file. My goal is to watch this file until a status line is printed, analyze line contents and return it to a human or Jenkins user. Of course, I can grep whole file and sleep for a second in a loop, but I'd rather avoid this if at all possible. Furthermore, this looping would interfere with my usage of timeout routine to limit maximum execution time. So, is it possible to listen for a pipe until a certain line appears and stop as soon as that happens?
Related question: Why does bash ignore SIGINT if its currently running child handles it?
Interesting question! I've verified that head dies after printing the first line (removed background job noise):
$ (printf '%s\n' a b a; sleep 5; printf '%s\n' a) | grep --line-buffered a | head --lines=1 & sleep 1; pstree $$
a
bash─┬─bash───sleep
├─grep
└─pstree
At first glance, it appears head doesn't send SIGPIPE, but I get conflicting information from running strace grep:
$ (printf '%s\n' a b a; sleep 10; printf '%s\n' a) | strace grep --line-buffered a | head --lines=1
…
--- SIGPIPE {si_signo=SIGPIPE, si_code=SI_USER, si_pid=21950, si_uid=1000} ---
+++ killed by SIGPIPE +++
… and killing grep:
$ (printf '%s\n' a b a; sleep 10; printf '%s\n' a) | grep --line-buffered a | head --lines=1 & sleep 1; kill -PIPE $(pgrep grep); sleep 5; pstree $$
a
bash─┬─bash───sleep
└─pstree
Killing grep and then sleep fixes the issue:
$ (printf '%s\n' a b a; sleep 10; printf '%s\n' a) | grep --line-buffered a | head --lines=1 & sleep 1; kill -PIPE $(pgrep grep); sleep 1; kill -PIPE $(pgrep sleep); sleep 5; pstree $$
a
bash───pstree
Conclusion: WTF?
I've ended up doing following to be able to break following log both on a matching line and after a timeout.
#!/bin/sh
TOP_PID=$$
container_id="$1"
LOG_PATH=/opt/jboss/jboss-eap-6.2/standalone/log/server.log
await_startup () {
status=$(check_status)
follow_log --timeout $timeout &
local bgjob_pid; local bgjob_status;
bgjob_pid=$(jobs -p)
test -n "$bgjob_pid" || die "Could not start background job to follow log."
bgjob_status=true
while [ "$status" = "not started" ] && $bgjob_status; do
sleep 1s
status=$(check_status)
if kill -0 $bgjob_pid 2>/dev/null; then
bgjob_status=true
else
bgjob_status=false
fi
done
kill -KILL $bgjob_pid 2>/dev/null
}
follow_log () {
# argument parsing skipped...
docker exec $container_id timeout $timeout tail --follow=name ---disable-inotify --max-unchanged-stats=2 /$LOG_PATH
}
check_status () {
local line;
line=$(docker exec $container_id grep --extended-regexp --only-matching 'JBoss EAP .+ started.+in' /$LOG_PATH | tail --lines=1)
if [ -z "$line" ]; then
printf "not started"
elif printf "%s" "$line" | grep --quiet "with errors"; then
printf "started and unhealthy"
else
printf "healthy"
fi
}
die () {
test -n "$1" && printf "%s\n" "$1"
kill -s TERM $TOP_PID
return 1
} 1>&2

In my bash script, how do I write a while loop that only exits if the output of "tail" doesn't contain a string?

I’m using Amazon Linux with bash shell. In my bash script, how do I construct a while loop that will spin so long as the command
tail -10 /usr/java/jboss/standalone/log/server.log
does not contain the string “FrameworkServlet ‘myprojectDispatcher': initialization completed”?
You can use:
tail -n 10 -f /usr/java/jboss/standalone/log/server.log |
awk '/FrameworkServlet.*myprojectDispatcher.*initialization completed/{exit} 1'
awk will exit when it encounters search string otherwise it will keep writing input to stdout.
However do keep in mind that the tail command is buffered and to avoid that behavior try stdbuf gnu utility:
stdbuf -i0 -o0 -e0 tail -n 10 -f /usr/java/jboss/standalone/log/server.log |
awk '/FrameworkServlet.*myprojectDispatcher.*initialization completed/{exit} 1'
I can try this:
#!/bin/bash
MATCH="FrameworkServlet ‘myprojectDispatcher': initialization completed"
while :
do
if tail /usr/java/jboss/standalone/log/server.log | grep -q "$MATCH"; then
exit 0
else
sleep 1
fi
done
while [ -nz grep -q "FrameworkServlet ‘myprojectDispatcher': initialization completed" /usr/java/jboss/standalone/log/server.log ]; do
# wait a second
sleep 1
done
# do the stuff
echo "we got it!"

PID Changing everytime I try to kill them

Hello I created a script to kill processes ordered by age however everytime the PIDs are changing... how can I solve this
here is my script
#!/bin/bash
#Argument = -c check -k kill -l list
usage()
{
cat << EOF
usage: $0 options
This script kills all the processes running and leaves the last one sorted by age running.
OPTIONS:
-c checks how many proccess are runnig it needs string argument
-k Kill all the processes and leaves just the last sorted by age running
-l Show the list of procesess to be killed.
EOF
}
CHECK=
KILL=
LIST=
while getopts "hc:k:l:" OPTION
do
case $OPTION in
h)
usage
exit 1
;;
c)
CHECK=$OPTARG
ps -ef | grep -i $CHECK | wc -l
;;
k)
KILL=$OPTARG
T2=$(ps -ef | grep -i "$KILL" | awk '{print $3,$5}' | sort -r +1 | sed 1d |awk '{print $1}')
for f in $T2; do
echo "killing $f"
kill $f
done
;;
l)
LIST=$OPTARG
T2=$(ps -ef | grep -i "$LIST" | awk '{print $3,$5}' | sort -r +1 | sed 1d |awk '{print $1}')
for f in $T2; do
echo "PID $f"
done
;;
?)
usage
exit
;;
esac
done
if [[ -z KILL ]] || [[ -z LIST ]] || [[ -z CHECK ]]
then
usage
exit 1
fi
and also I don't understand why when I call the script with no arguments the help doesn't show up
The PIDs will change if another program is restarting it when it's killed. This is actually pretty common with daemons.
usage is never called because you're checking whether the strings KILL etc. are empty, not the variables. Just add a dollar sign in front of them.

Resources