Ping a host and output in CSV format in bash - bash

I have a CSV file named ip.csv in the following format:
Host,Status
192.168.0.2
192.168.0.4
I want to ping IP and save output in the same file, ip.csv, next to the host. Output should look like:
Host,Status
192.168.0.2,Alive
192.168.0.4,Down
When I executed below script, I didn't get desired output:
#!/bin/bash
while IFS=',' read -r host status
do
ping -c 1 "$host"
if [ $? -eq 0 ]; then
echo -e "$host,Alive" >> ip.csv
else
echo -e "$host,Down" >> ip.csv
fi
done < ip.csv
Please suggest.

you can do it using this changes -
#!/bin/bash
a=""
while IFS=',' read -r host status
do
if [ "$host" = "Host" ]; then
a="${a}${host}"','"${status}"$'\n'
else
ping -c 1 "$host"
if [ $? -eq 0 ]; then
a="${a}${host}"',Alive'$'\n'
else
a="${a}${host}"',Down'$'\n'
fi
fi
done < ip.csv
echo -e "${a}" > ip.csv

Related

Bash Script - Integer expression expected

With the below code, I keeping getting:
line 9: [: 8.8.8.8: integer expression expected
Unsure Why?
#!/bin/bash
sourceFile="file.log"
targetFile="2file.log"
ping="8.8.8.8"
while IFS='' read -r line || [[ -n "$line" ]]; do
echo "$line" >> "$targetFile"
sudo service networking restart
ping -q -c 5 "$ping"
if [ "$ping" -ne 0 ]; then
sed -n -e 8p "$2file.log"
fi
done < "$sourceFile"
Because you are trying to compare "8.8.8.8" (string) to 0 (integer)
ping="8.8.8.8"
if [ "$ping" -ne 0 ]; then
ping variable is string.
You are comparing a string value ("8.8.8.8") to an integer value (0)
You can retrieve the exit code of your ping command with $?
ping="8.8.8.8"
ping -q -c 5 "$ping"
ping=$?
if [ $ping -ne 0 ]; then
echo "NOTOK"
else
echo "OK"
fi
Check this post

shell script to check for multiple files with different names

I am creating a script to check for 3 files in Directory, take the count of rows in them and mail if the rows exist.I have to send only one mail if either of these files have count, I am ending up sending 3 mails.
For Ex. I have these files
process_date.txt
thread_date.txt
child_date.txt
Iam doing something like
$1= process_date.txt
$2= thread_date.txt
$3= child_date.txt
if [ -f $1 ]
then
count1=`wc-l < $1`
if $count1 -ne 0 then mailx abc.com
fi
fi
if [ -f $2 ]
then
count2=`wc-l < $2`
if $count2 -ne 0 then mailx abc.com
fi
fi
if [ -f $3 ]
then
count3=`wc-l < $3`
if $count3 -ne 0 then mailx abc.com
fi
fi
As you stated your question, it seems you only need to check whether at least one of the files is non-empty: you don't need to count the number of rows. In Bash, you may use the [[ -s file ]] test to exactly test whether file exists and is non-empty. So you can do:
#!/bin/bash
if [[ -s $1 ]] || [[ -s $2 ]] || [[ -s $3 ]]; then
mailx abc.com
fi
More generally, you can have the mail sent if at least one of the files given as arguments exists and is non-empty:
#!/bin/bash
for file; do
if [[ -s $file ]]; then
mailx abc.com
break
fi
done
You'll call this as
scriptname process_date.txt thread_date.txt child_date.txt
You can wrap your script in a function and use return command after every mailx, like this:
send_one_mail() {
if [ -f "$1" ]
then
count1=$(wc -l < "$1")
if [ $count1 -ne 0 ]
then
mailx abc.com
return
fi
fi
# etc. for other conditions
}
send_one_mail process_date.txt thread_date.txt child_date.txt
Try this:
if [ -f $1 ]
then
count1=`wc -l < $1`
fi
if [ -f $2 ]
then
count2=`wc -l < $2`
fi
if [ -f $3 ]
then
count3=`wc -l < $3`
fi
if [ $count1 -ne 0 -o $count2 -ne 0 -o $count3 -ne 0 ]
then
mailx abc.com
fi

Conditional statement bash script

I need help with replacing the following script with a different format where a configuration file, and a loop is used.
[FedoraC]$ cat script.sh
#!/bin/bash
grep -q /tmp /etc/fstab
if [ $? -eq 0 ]; then
echo "True"
else
echo "False"
fi
mount | grep ' /tmp' | grep nodev
if [ $? -eq 0 ]; then
echo "True"
else
echo "False"
fi
mount | grep /tmp | grep nosuid
if [ $? -eq 0 ]; then
echo "True"
else
echo "False"
fi
So far I have the following script which should take the values from a source/conf file and run each command found in the conf file one by one. After the command is executed the output would be "True" or "False"
conf file is formed by Unix commands: /opt/conf1
[FedoraC]$ cat conf1
grep -q /tmp /etc/fstab
mount | grep /tmp | grep nodev
mount | grep /tmp | grep nosuid
mount | grep /tmp | grep noexec
[FedoraC]$ cat new_script.sh
#!/bin/bash
. conf1
for i in $#;
do $i
if [ $i -eq 0 ]; then
echo "Passed"
else
echo "Failed"
fi
done
Instead of displaying the output based on the conditional statement, the script runs each line one by one from conf1, and not echo messages are seen.
Can I get some help please.
try this:
#! bin/bash
while read L; do
echo $L'; exit $?'|sh
if [ $? -eq 0 ]; then
echo Pass
else
echo Failed
fi
done < conf1
The more robust and canonical way to do this would be to have a directory /opt/conf1.d/, and put each of your lines as an executable script in this directory. You can then do
for file in /opt/conf1.d/*
do
[[ -x $file ]] || continue
if "$file"
then
echo "Passed"
else
echo "Failed"
fi
done
This has the advantages of supporting multi-line scripts, or scripts with more complex logic. It also lets you write the check script in any language, and lets scripts and packages add and remove contents easily and non-interactively.
If you really want to stick with your design, you can do it with:
while IFS= read -r line
do
if ( eval "$line" )
then
echo "Passed"
else
echo "Failed"
fi
done < /opt/conf1
The parentheses in the if statement runs eval in a subshell, so that lines can't interfere with each other by setting variables or exiting your entire loop.

sh variable not working if blank

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

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"

Resources