sh variable not working if blank - bash

Need some extra eyes for this one...
dns_lookup() {
ip_set
if [ `ip_ping ${ip_address}` -eq 0 ]
then
host=""
dig +short -x ${ip_address} | sed 's/\.$//g' | while read host
do
if [ -z "${host}" ]
then
host="unknown"
fi
echo "${ip_address},${host}"
done
fi
}
I get desired results if ip is pingable and has a dns name. I do not get results if the ip is pingable but does not have a dns name.
ip_set() {
ip_address="${a}.${b}.${c}.${d}"
}
ip_ping() {
timeout ${delay} ping -q -c 1 -i 1 -W 1 -w 4 $1 > /dev/null 2>&1 ; echo $?
}

Perhaps this is what you need. Tell me if you need revisions.
dns_lookup() {
ip_set
if [ `ip_ping ${ip_address}` -eq 0 ]
then
host=""
dig +short -x ${ip_address} | sed 's/\.$//g' | {
hashosts=false
while read host
do
if [ -n "${host}" ]
then
hashosts=true
echo "${ip_address},${host}"
fi
done
[ "${hashosts}" = false ] && echo "${ip_address},unknown"
}
fi
}
I would have also suggested the change of function ip_ping but that_other_guy already did it.

You don't get a result when there's no hostname because your while read loop never runs when there are no lines to read. You should make your printing code run regardless:
host=$(dig +short -x "${ip_address}" | sed 's/\.$//g')
if [ -z "${host}" ]
then
host="unknown"
fi
printf "${ip_address},%s\n" $host
Also, you're going about your condition wrong. You shouldn't echo the exit status and compare it as text. You should just let your command's exit status be your function's exit status:
ip_ping() {
timeout ${delay} ping -q -c 1 -i 1 -W 1 -w 4 $1 > /dev/null 2>&1
# functions implicitly 'return $?' if you don't specify anything else
}
Now you can easily check your function:
if ip_ping "$ip_address"
then
echo "It worked"
else
echo "It failed.."
fi

Related

Linux Command Results in a bash Variable

I am trying to write a Ping result bash code.
this way it work, but i'm not a fan of using the last ouput function:
#!/bin/bash
ping -q -c2 10.10.50.120 > /dev/null
resp=$?
echo "$resp"
if [ "$resp" == 0 ]
then
echo "ok"
else
echo "not ok"
fi
Ouput:
0
ok
but this way it doesn't work:
#!/bin/bash
resp=$(ping -q -c2 10.10.50.120 > /dev/null)
echo "$resp"
if [ "$resp" == 0 ]
then
echo "ok"
else
echo "not ok"
fi
Ouput:
not ok
Can anyone help me to find out how to write it correctly?
I wanted to avoid the "$?" function.
That's great. So just use if.
if output=$(ping -q -c2 10.10.50.120); then
# or like: if ping -q -c2 10.10.50.120 >/dev/null; then
echo "ok"
else
echo "not ok"
fi
echo "Anyway, ping command ouptutted: $output"
It is possible to save the exit status to a variable without the "$?" function?
No.

Nested if statement inside a for loop in bash script

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

Bash | Host-check

I have a little problem with my bash script
i got a school project where i have to make a bash script to check if the host is up every 5 minuttes and if fails send email
i had problems with the "fi" statement but fixed the error.
now when i run the script i get an error: line 17 to many arguments"
it initiate the ping command (my Anti virus is blocking the ICMP, so i know the ping lines work)
#!/bin/bash
#Server-status script
FAILS=0
EMAIL_ADDRESS="Critical-error#gruppe4.net" ##Email capabilities
SERVER="192.168.1.1" ###Host to check
SLEEP=300 ###Defining Sleep
while true; do
ping -c 1 $SERVER >/dev/null 2>&1
if [ $? -ne 0 ] ; then #if ping exits nonzero...
FAILS=$"[FAILS + 1]"
else
FAILS=0
fi
if [ $FAILS -gt 4 ]; then
FAILS=0
echo "Server $SERVER is offline!" \
| mail -s "Server offline" "$EMAIL_ADDRESS"
fi
sleep $SLEEP #check again in SLEEP seconds
done
use declare -i to use FAILS as integer and initialize to 0
declare -i FAILS=0
then sum 1
FAILS=$FAILS+1
here is my code(I've commented the mail commmand):
#!/bin/bash
#Server-status script
declare -i FAILS=0
EMAIL_ADDRESS="Critical-error#gruppe4.net" ##Email capabilities
SERVER="192.168.1.1" ###Host to check
SLEEP=1 ###Defining Sleep
echo "1-FAILS[$FAILS]"
while true; do
ping -c 1 $SERVER >/dev/null 2>&1
if [ $? -ne 0 ] ; then #if ping exits nonzero...
FAILS=$FAILS+1
else
FAILS=0
fi
echo "2-FAILS[$FAILS]"
if [ $FAILS -gt 1 ]; then
FAILS=0
echo "Server $SERVER is offline!" # \ | mail -s "Server offline" "$EMAIL_ADDRESS"
fi
sleep $SLEEP #check again in SLEEP seconds
done
output:
sh-4.3$ bash -f main.sh
1-FAILS[0]
2-FAILS[1]
2-FAILS[2]
Server 192.168.1.1 is offline!
2-FAILS[1]
2-FAILS[2]
Server 192.168.1.1 is offline!
2-FAILS[1]
2-FAILS[2]
Server 192.168.1.1 is offline!
2-FAILS[1]
I hope this can help
Regards
Claudio
You are expanding the $FAILS variable with content [FAILS + 1], getting an invalid [] syntax.
Change FAILS=$"[FAILS + 1]" to:
FAILS=$((FAILS+1))

Bash remote files system directory test

the more I learn bash the more questions I have, and the more I understand why very few people do bash. Easy is something else, but I like it.
I have managed to figure out how to test directories and there writablity, but have a problem the minute I try to do this with a remote server over ssh. The first instance testing the /tmp directory works fine, but when the second part is called, I get line 0: [: missing]'`
Now if I replace the \" with a single quote, it works, but I thought that single quotes turn of variable referencing ?? Can someone explain this to me please ? Assuming that the tmp directory does exist and is writable, here the script so far
#!/bin/bash
SshHost="hostname"
SshRsa="~/.ssh/id_rsa"
SshUser="user"
SshPort="22"
Base="/tmp"
Sub="one space/another space"
BaseBashExist="bash -c \"[ -d \"$Base\" ] && echo 0 && exit 0 || echo 1 && exit 1\""
SSHBaseExist=$( ssh -l $SshUser -i $SshRsa -p $SshPort $SshHost ${BaseBashExist} )
echo -n $Base
if [ $? -eq 0 ]
then
echo -n "...OK..."
else
echo "...FAIL"
exit 1
fi
BaseBashPerm="bash -c \"[ -w \"$Base\" ] && echo 0 && exit 0 || echo 1 && exit 1\""
SSHBaseExist=$( ssh -l $SshUser -i $SshRsa -p $SshPort $SshHost ${BaseBashPerm} )
if [ $? -eq 0 ]
then
echo "...writeable"
else
echo "...not writeable"
fi
BaseAndSub="$Base/$Sub"
BaseAndSubBashExist="bash -c \"[ -d \"$BaseAndSub\" ] && echo 0 && exit 0 || echo 1 && exit 1\""
SSHBaseAndSubExist=$( ssh -l $SshUser -i $SshRsa -p $SshPort $SshHost ${BaseAndSubBashExist} )
echo -n $BaseAndSub
if [ $? -eq 0 ]
then
echo -n "...OK..."
else
echo "...FAIL"
exit 1
fi
BaseAndSubBashPerm="bash -c \"[ -w \"$BaseAndSub\" ] && echo 0 && exit 0 || echo 1 && exit 1\""
SSHBaseAndSubPerm=$( ssh -l $SshUser -i $SshRsa -p $SshPort $SshHost ${BaseAndSubBashPerm} )
if [ $? -eq 0 ]
then
echo -n "...writeable"
else
echo "...not writeable"
fi
exit 0
The first thing you should do is refactor your code with simplicity in mind, then the quoting error will go away as well. Try:
if ssh [flags] test -w "'$file'"; then
Encapsulate your SSH flags in a ssh config to facilitate re-use, and your script will shorten dramatically.
You are fine with single quotes in this context; by the time the script is seen by the remote bash, your local bash has already substituted in the variables you want to substitute.
However, your script is a total mess. You should put the repetitive code in functions if you cannot drastically simplify it.
#!/bin/bash
remote () {
# most of the parameters here are at their default values;
# why do you feel you need to specify them?
#ssh -l "user" -i ~/.ssh/id_rsa -p 22 hostname "$#"
ssh hostname "$#"
# —---------^
# if you really actually need to wrap the remote
# commands in bash -c "..." then add that here
}
exists_and_writable () {
echo -n "$1"
if remote test -d "$1"; then
echo -n "...OK..."
else
echo "...FAIL"
exit 1
fi
if remote test -w "$1"; then
echo "...writeable"
else
echo "...not writeable"
fi
}
Base="/tmp"
# Note the need for additional quoting here
Sub="one\\ space/another\\ space"
exists_and_writable "$Base"
BaseAndSub="$Base/$Sub"
exist_and_writable "$BaseAndSub"
exit 0
ssh -qnx "useraccount#hostname"
"test -f ${file absolute path} ||
echo ${file absolute path} no such file or directory"

Check if program is running with bash shell script?

This is an example of a bash script which checks for some running process (daemon or service) and does specific actions (reload, sends mail) if there is no such process running.
check_process(){
# check the args
if [ "$1" = "" ];
then
return 0
fi
#PROCESS_NUM => get the process number regarding the given thread name
PROCESS_NUM='ps -ef | grep "$1" | grep -v "grep" | wc -l'
# for degbuging...
$PROCESS_NUM
if [ $PROCESS_NUM -eq 1 ];
then
return 1
else
return 0
fi
}
# Check whether the instance of thread exists:
while [ 1 ] ; do
echo 'begin checking...'
check_process "python test_demo.py" # the thread name
CHECK_RET = $?
if [ $CHECK_RET -eq 0 ]; # none exist
then
# do something...
fi
sleep 60
done
However, it doesn't work. I got "ERROR: Garbage option." for the ps command. What's wrong with these scripts? Thanks!
You can achieve almost everything in PROCESS_NUM with this one-liner:
[ `pgrep $1` ] && return 1 || return 0
if you're looking for a partial match, i.e. program is named foobar and you want your $1 to be just foo you can add the -f switch to pgrep:
[[ `pgrep -f $1` ]] && return 1 || return 0
Putting it all together your script could be reworked like this:
#!/bin/bash
check_process() {
echo "$ts: checking $1"
[ "$1" = "" ] && return 0
[ `pgrep -n $1` ] && return 1 || return 0
}
while [ 1 ]; do
# timestamp
ts=`date +%T`
echo "$ts: begin checking..."
check_process "dropbox"
[ $? -eq 0 ] && echo "$ts: not running, restarting..." && `dropbox start -i > /dev/null`
sleep 5
done
Running it would look like this:
# SHELL #1
22:07:26: begin checking...
22:07:26: checking dropbox
22:07:31: begin checking...
22:07:31: checking dropbox
# SHELL #2
$ dropbox stop
Dropbox daemon stopped.
# SHELL #1
22:07:36: begin checking...
22:07:36: checking dropbox
22:07:36: not running, restarting...
22:07:42: begin checking...
22:07:42: checking dropbox
Hope this helps!
If you want to execute that command, you should probably change:
PROCESS_NUM='ps -ef | grep "$1" | grep -v "grep" | wc -l'
to:
PROCESS_NUM=$(ps -ef | grep "$1" | grep -v "grep" | wc -l)
PROCESS="process name shown in ps -ef"
START_OR_STOP=1 # 0 = start | 1 = stop
MAX=30
COUNT=0
until [ $COUNT -gt $MAX ] ; do
echo -ne "."
PROCESS_NUM=$(ps -ef | grep "$PROCESS" | grep -v `basename $0` | grep -v "grep" | wc -l)
if [ $PROCESS_NUM -gt 0 ]; then
#runs
RET=1
else
#stopped
RET=0
fi
if [ $RET -eq $START_OR_STOP ]; then
sleep 5 #wait...
else
if [ $START_OR_STOP -eq 1 ]; then
echo -ne " stopped"
else
echo -ne " started"
fi
echo
exit 0
fi
let COUNT=COUNT+1
done
if [ $START_OR_STOP -eq 1 ]; then
echo -ne " !!$PROCESS failed to stop!! "
else
echo -ne " !!$PROCESS failed to start!! "
fi
echo
exit 1

Resources