This question already has an answer here:
checking if grep command returns correct output
(1 answer)
Closed 7 years ago.
I have done a file named hosts.txt which includes some websites, to test the ping on each website with a script. What I want to do with my script is I want to loop through each line that includes different websites, and it should tell if the website is up or down (by measuring the ping command on each)
What my problem is that I don't really know how to get the return value of the ping command, so in case a website is up it should say "'website name' found" or not found. I have been researching, also tried out the ! command and different ways in the if-statement, but none of them seem to work.
My code:
#!/bin/bash
echo
echo "Monitoring hosts from file hosts.txt ..."
echo
echo
egrep -v '^(#|$)' hosts.txt | while read line; do #put the egrep value
#which is the lines in hosts.txt, and loop through each one of them
if [ ping $line ];then
echo "$line is up"
else
echo "$line is not up"
fi
done
echo
You need to use the $? special variable.
For example:
ping $line
pingResponse = $?
if [ $pingResponse -eq 0 ];then
echo "$line is up"
else
echo "$line is not up"
fi
you can test for boolean like:
[[ `ping $line` ]]
.
#!/bin/bash
echo
echo "Monitoring hosts from file hosts.txt ..."
echo
echo
egrep -v '^(#|$)' hosts.txt | while read line; do #put the egrep value
#which is the lines in hosts.txt, and loop through each one of them
if [[ `ping $line` ]];then
echo "$line is up"
else
echo "$line is not up"
fi
done
Related
I'm trying to write a script that allows you to enter your machine name, and then lets you know if the host is on the local network. Here's what I have:
#!/bin/bash
echo "Please enter the host you would like to ping:"
read -r host
output=$(ruptime | awk '{print $1}')
if [ "$output" == "$host" ];
then
echo "$host is up"
else
echo "$host is down"
fi
This works when I enter my machine name 'ubuntu' since I am the only one on my LAN and the awk statement outputs 'ubuntu'.
If I run for example:
#!/bin/bash
echo "Please enter the host you would like to ping:"
read -r host
output=$(cat /etc/hosts | awk '{print $1}')
if [ "$output" == "$host" ];
then
echo "$host is up"
else
echo "$host is down"
fi
The output is 2 lines: localhost and ubuntu. If I then run the script and enter either one of those, it says it's not found.
I think the awk is only looking for the value in the first line. How can I have the script check every line from the output of the awk and then compare it to what was entered?
Thanks in advance!
You're setting $output to all the names. You're not checking if $host is one of them, you're checking if $host is equal to all of them at once.
grep is a better way to do this.
if ruptime | grep -q -w "$host"
then echo "$host is up"
else echo "$host is down"
fi
Assuming that your goal is to look at whether a given name is in the first column of the output from ruptime, that might look like:
#!/usr/bin/env bash
hostname="target"
while read -r hostname _; do
[[ $hostname = "$target" ]] && { echo "$target is up"; break; }
done < <(ruptime)
read -r hostname _ puts only the first column of each line into hostname, putting remaining text into _.
I have application which register OnLine or Offline status which is stored in my test.log file. Status can be changed every second or minute or at all during many hours. Once per 15 minutes I need to send actual status to external machine [my.ip.address]. In below example let's assume that I need to just echo actual status.
I wrote below script which is watching my test.log and stores actual status in FLAG variable. However I cannot send it (or echo) to my external machine [my.ip.address] cause FLAG is not saved properly. Do you have any idea what's wrong in below example?
#!/usr/bin/env bash
FLAG="OffLine"
FLAG_tmp=$FLAG
tail -f /my/path/test.log | while read line
do
if [[ $line == *"OnLine"* ]]; then
FLAG_tmp="OnLine"
fi
if [[ $line == *"OffLine"* ]]; then
FLAG_tmp="OffLine"
fi
if [ "$FLAG" != "$FLAG_tmp" ];then
FLAG=$FLAG_tmp
echo $FLAG # it works, now FLAG stores actual true status
fi
done &
# till this line I suppose that everything went well but here (I mean out of
# tail -f scope) $FLAG stores only OffLine - even if I change it to OnLine 4 lines before.
while :
do
#(echo $FLAG > /dev/udp/[my.ip.address]/[port])
echo "$FLAG" # for debug purpose - just echo actual status.
# However it is always OffLine! WHY?
#sleep 15*60 # wait 15 minutes
sleep 2 # for debug, wait only 2 sec
done
EDIT:
Thanks guys for your answers, but I still don't get a solution.
#123: I corrected my code basing on your example, but it seems to not working.
#!/usr/bin/env bash
FLAG="OffLine"
FLAG_tmp=$FLAG
while read line
do
if [[ $line == *"OnLine"* ]]; then
FLAG_tmp="OnLine"
fi
if [[ $line == *"OffLine"* ]]; then
FLAG_tmp="OffLine"
fi
if [ "$FLAG" != "$FLAG_tmp" ];then
FLAG=$FLAG_tmp
#echo $FLAG
fi
done & < <(tail -f /c/vagrant_data/iso/rpos/log/rpos.log)
while :
do
echo "$FLAG"
sleep 2
done
#chepner: Do you have some exact proposals how can I solve this problem?
I think you are making it overly complicated. If you just want to send yourself the last state of OffLine or OnLine you might try something like this:
#!/bin/bash
while :
do
FLAG="$(egrep 'OffLine|OnLine' test.log | tail -1)"
if [ $(echo "$FLAG" | grep OffLine) ]
then
FLAG=OffLine
else
FLAG=OnLine
fi
echo $FLAG
sleep 2
done
Or, if you really want to keep the two processes,
#!/bin/bash
echo OffLine > status
tail -f test.log | while read line
do
if [[ "$line" =~ "OffLine" ]]
then
echo OffLine > status
elif [[ "$line" =~ "OnLine" ]]
then
echo OnLine > status
fi
done &
while :
do
cat status > /dev/udp/[my.ip.address]/[port])
sleep 15*60
done
I'm writing a bash script that goes through a for loop which is a list of each hostname, then will test each one if it's responding on port 22, if it is then execute an ssh session, however both the first and second if statements are only executed on the first host in the list, not the rest of the hosts. If the host isn't responding on port 22, I want the script to continue to the next host. Any ideas how to ensure the script runs the ssh on each host in the list? Should this be another for loop?
#!/bin/bash
hostlist=$(cat '/local/bin/bondcheck/hostlist_test.txt')
for host in $hostlist; do
test=$(nmap $host -P0 -p 22 | egrep 'open|closed|filtered' | awk '{print $2}')
if [[ $test = 'open' ]]; then
cd /local/bin/bondcheck/
mv active.current active.fixed
ssh -n $host echo -n "$host: ; cat /proc/net/bonding/bond0 | grep Active" >> active.current
result=$(comm -13 active.fixed active.current)
if [ "$result" == "" ]; then
exit 0
else
echo "$result" | cat -n
fi
else
echo "$host is not responding"
fi
done
exit 0 exits the entire script; you just want to move on to the next iteration of the loop. Use continue instead.
You problem is most likely in the lines
if [ "$result" == "" ]
then
exit 0
else
echo "$result" | cat -n
fi
Here the exit 0 causes the entire script to exit when the $result is empty. You could the way around using :
if [ "$result" != "" ] #proceeding on non-empty 'result'
then
echo "$result" | cat -n
fi
This question already has answers here:
A variable modified inside a while loop is not remembered
(8 answers)
Closed 6 years ago.
I'm trying to loop through allURLs.txt and check if every entry in that file exists in PDFtoCheck.pdf. I know of a tool called pdfgrep, but can't seem to apply it to suit my objective.
#!/bin/bash
entriesMissing=0;
cat allURLs.txt | while read line
do
# do something with $line here
if [ ! -z echo `pdfgrep "$line" PDFtoCheck.pdf` ];
then
echo "yay $line";
else
echo "$line not found";
entriesMissing=$[$entriesMissing+1];
fi
done
echo "DONE";
echo "There are $entriesMissing entries missing!";
Despite placing dummy values in allURLs.txt, entires which are present in allURLs.txt but not in PDFtoCheck.pdf are not reflected in the output. Any idea how to make it work as intended?
Please note that a subshell is created when piping: cat file | while. You should use file redirection instead: while ... do; done < file.
As far as I can see pdfgrep supports the -q quiet flag, so you can just use it in the if-statement.
entriesMissing=0
while IFS= read -r line; do
if pdfgrep -q -- "$line" PDFtoCheck.pdf; then
printf "Found '%s'\n" "$line"
else
printf "'%s' not found\n" "$line"
((entriesMissing++))
fi
done < allURLs.txt
printf "There are %d entries missing\n" "%entriesMissing"
I also changed the increment to ((... ++))
Extending my comment as answer. I'm using -c option which is also available in pdfgrep :
entriesMissing=0
while read line
do
# do something with $line here
if [ $(grep -c "$line" b) -eq 0 ]
then
((entriesMissing++))
echo "$line not found"
else
echo "yay $line"
fi
done < allURLs.txt
echo "DONE"
echo "There are $entriesMissing entries missing!";
One thing I want point out in your code that you are incrementing entriesMissing inside a subshell(pipe) which doesn't get reflected at the last line. Hope it helps.
I wrote a little bash script called "wp", which upload files to an ftp server. It uses the wput utility. It takes the list of files from a text file. When uploading is ready it comments out the line with a double cross in the text file. The success of the upload is detected according to the last line in the logfile. My question is how can I avoid multiple starting of my script? I am trying to detect with pgrep if the instance is running, but doesn't work correctly:
#!/bin/bash
if [ "$(pgrep ^wp$|wc -l)" -eq "2" ]
then
echo "$(pgrep ^wp$)"
echo "$(pgrep ^wp$|wc -l)"
echo "wp script is starting..."
else
echo "$(pgrep ^wp$)"
echo "$(pgrep ^wp$|wc -l)"
echo "wp script is already running!"
exit
fi
server="ftp://username:password#ftp.ftpserver.com"
logfile=~/uploads.log
listfile=~/uploads.txt
list_backup=~/uploads_bak000.txt
while read f;
do
ret=""
if [ "${f:0:1}" = "#" -o "$f"1 = 1 ]
then
if [ "$f"1 = 1 ]
then
:
#echo "invalid string: "$f
else
#first character is remark sign # then empty command -> :
echo "remark line skipped: "$f
fi
else
#while string $ret is empty
while [ -z "$ret" ]
do
wput "$f" --tries=-1 "$server" 2>&1|tee -a $logfile #> /dev/null
ret=$(tail -n 1 "$logfile"|grep "FINISHED\|Nothing\|Skipped\|Transfered")
done
if [ -n "$ret" ]
then
cat $listfile > $list_backup
awk -v f="$f" '{if ($0==f && $0!~/#/) print "#" $0; else print $0;}' $list_backup > $listfile
fi
fi
done < $listfile
There are quick-n-dirty solutions that use ps with grep (don't do this).
It is better to use a lock file as a "mutex". A nice way of doing this is by using a directory as a lock file (http://mywiki.wooledge.org/BashFAQ/045).
I would also suggest taking a look at:
http://mywiki.wooledge.org/ProcessManagement#How_do_I_make_sure_only_one_copy_of_my_script_can_run_at_a_time.3F
, which mentions use of setlock(http://cr.yp.to/daemontools/setlock.html) that abstracts the lock file handling for you.