Is there a way to display function output in bash command - bash

Have a simple bash script I am working on with Mac, but I am having one issue.
#!/bin/bash
# Pull users IP from getifaddr on specfic port
myip ( ) {
#ipconfig getifaddr ppp0
local _ip _myip _line _nl=$'\n'
while IFS=$': \t' read -a _line ;do
[ -z "${_line%inet}" ] &&
_ip=${_line[${#_line[1]}>4?1:2]} &&
[ "${_ip#127.0.0.1}" ] && _myip=$_ip
done< <(LANG=C /sbin/ifconfig)
printf ${1+-v} $1 "%s${_nl:0:$[${#1}>0?0:1]}" $_myip
}
printf "My ip: %"
myip
# Static server IP stored
serverip ( ) {
echo 192.168.12.110
}
serverip
## Command to add them together
sudo route add $myip $severip
So far the functions work, but the sudo route command does not since I am guessing there is no return value.
What I need it to do it output the myip IP address and the serverip IP address onto the line so the command can run in a single command.
For example: sudo route add 192.168.0.1 192.168.0.2
Right now, it tells me "myip is not a valid routing address" as I believe it is taking the literal 4 character string "myip" and not the IP address.

Bash's command substitution might help:
sudo route add $(myip) $(serverip)

Related

bash - using a command line argument (hostname) to run an external command

First time post, please forgive any missing information.
I have a script that is supposed to work with icinga. I need icinga to log into my Linux box and run a command like "script ". The script will then run a command to that hostname like sudo /etc/init.d/apache2 status then report back "running or unused" and an exit status of 0 or 2.
I'm wondering how I could add another command and have it one or the other run depending on what hostname it's given. Half of them need apache2 to be running and the other half need to have a process called dss to be running. I'd rather not have two separate scripts. Here is the working script and sorry it's sloppy but I haven't done any clean up and I'm not real good at bash yet.
so the user would run the script ./chkdss2 or
#!/bin/bash
ec=0
ec1=2
var3=run
var4=unused
for host in "$#"
do
var1=`ssh $host sudo /etc/init.d/dss status|awk '{print $6}'`
var2="$( echo $var1 | cut -c 3-5 )"
if [[ "$var2" == "$var3" ]]; then
echo "$host is running"
echo $ec
else
echo "$host is not running"
echo $ec1
fi
done
There are a couple ways to test if a particular hostname is for apache or dss. You only need to have a list of hostnames for each case, and check if the received hostnames are included in said lists.
Method 1: using arrays
#!/bin/bash
# Method 1, using array lists of hosts
apachehosts=('ap1' 'ap2' 'ap3')
dsshosts=('dss1' 'dss2' 'dss3')
for host in "$#"
do
if printf '%s\n' "${apachehosts[#]}" | grep -Fxq "$host"
then
echo "$host: APACHE HOST"
elif printf '%s\n' "${dsshosts[#]}" | grep -Fxq "$host"
then
echo "$host: DSS HOST"
else
echo "ERROR, $host: unknown host"
fi
done
To modify the lists of hosts, simply add or remove values in the declaration of arrays apachehosts and dsshosts.
Method 2: using case
#!/bin/bash
# Method 2, using case
for host in "$#"
do
case "$host" in
'ap1'|'ap2'|'ap3')
echo "CASE, $host: APACHE HOST"
;;
'dss1'|'dss2'|'dss3')
echo "CASE, $host: DSS HOST"
;;
*)
echo "ERROR CASE, $host: unknown host"
;;
esac
done
Here, you edit the patterns in each case.
Method 3: using if
#!/bin/bash
# Method 3, using if
for host in "$#"
do
if [[ "$host" == 'ap1' || "$host" == 'ap2' || "$host" == 'ap3' ]]
then
echo "IF, $host: APACHE HOST"
elif [[ "$host" == 'dss1' || "$host" == 'dss2' || "$host" == 'dss3' ]]
then
echo "IF, $host: DSS HOST"
else
echo "IF, $host: unknown host"
fi
done
Here you modify the if conditions. I prefer the other methods, since this one is more complicated to edit, it is not as clear, especially if your list of hosts is long.
Method 4: condition on the hostnames
If you are lucky, there is some pattern to your hostnames. Ex. all apache servers start with letters ap, all your dss servers include dss in the name, ...
You can then simply use 2 if statements to decide which is which.
#!/bin/bash
# Method 4, patterns
for host in "$#"
do
if [[ $(echo "$host" | grep -c -e "^ap") -ne 0 ]]
then
echo "PATTERNS, $host: APACHE HOST"
elif [[ $(echo "$host" | grep -c -e "dss") -ne 0 ]]
then
echo "PATTERNS, $host: DSS host"
else
echo "PATTERNS, $host: unknown host"
fi
done
Note: hostname apdss1 would come out as an Apache server here. Previous methods would respond "unknown host". You patterns must be strict enough to avoid mismatches.
I had a similar task to get few report items using single ssh request.
I had to retrieve in singel ssh command:
Full hostname (FQDN)
Linux version
IP address of its Docker host if exist, or "none"
I got my script to work in 3 stage.
1. Get multiple lines of information from remote host
ssh -q dudi-HP-Compaq-Elite-8300-MT <<< '
date +%F:%T # line 1: time stamp
hostname -f # line 2: hostname
awk "/DESCR/{print \$3}" /etc/lsb-release # line 3 : host linux distribution version
ip a | awk "/inet / && !/127.0.0.1/{sub(\"/.*\",\"\",\$2);printf(\"%s \", \$2)}" # line 4: list IP address to the host
'
Results:
2022-03-05:22:22:21
dudi-HP-Compaq-Elite-8300-MT
20
192.168.2.111 192.168.122.1 172.17.0.1
2. Process multiple lines of information from remote host
Read lines of information from remote host, into an array sshResultsArr.
readarray -t sshResultsArr < <(ssh -q dudi-HP-Compaq-Elite-8300-MT <<< '
date +%F:%T # line 1: time stamp
hostname -f # line 2: hostname
awk "/DESCR/{print \$3}" /etc/lsb-release # line 3 : host linux distribution version
ip a | awk "/inet / && !/127.0.0.1/{sub(\"/.*\",\"\",\$2);printf(\"%s \", \$2)}" # line 4: list IP address to the host
')
hostname=${sshResultsArr[1]}
osVersion=${sshResultsArr[2]}
hasDockerIp=$(grep -Eo "172(.[[:digit:]]{1,3}){3}" <<< "${sshResultsArr[3]}") # find IP starting with 172
hasDockerIp=${hasDockerIp:="none"} # if not found IP set to "NONE"
printf "%s \t OS version: %s \t has Docker IP: %s\n" "$hostname" "$osVersion" "$hasDockerIp"
Result:
dudi-HP-Compaq-Elite-8300-MT OS version: 20 has Docker IP: 172.17.0.1
3. Process each remote host in a loop
#!/bin/bash
for host in "$#"; do
readarray -t sshResultsArr < <(ssh -q $host <<< '
date +%F:%T # line 1: time stamp
hostname -f # line 2: hostname
awk "/DESCR/{print \$3}" /etc/lsb-release # line 3 : host linux distribution version
ip a | awk "/inet / && !/127.0.0.1/{sub(\"/.*\",\"\",\$2);printf(\"%s \", \$2)}" # line 4: list IP address to the host
')
hostname=${sshResultsArr[1]}
osVersion=${sshResultsArr[2]}
hasDockerIp=$(grep -Eo "172(.[[:digit:]]{1,3}){3}" <<< "${sshResultsArr[3]}") # find IP starting with 172
hasDockerIp=${hasDockerIp:="none"} # if not found IP set to "NONE"
printf "%s \t OS version: %s \t has Docker IP: %s\n" "$hostname" "$osVersion" "$hasDockerIp"
done
I was able to take a little bit from the answers I received and put together something that works well. Thank you all for your answers.
for host in "$#"
do
case "$host" in
('vho1uc1-primary'|'vho1uc2-backup'|'vho2uc1-primary'|'vho2uc2-backup'|'vho3uc1-primary'|'vho3uc2-backup'|'vho10uc1-primary')
var1=`ssh "$host" sudo /etc/init.d/apache2 status|awk '{print $4}'`
var2="$( echo $var1 | cut -c 3-5 )"
if [[ "$var2" == "$var3" ]]; then
echo "Apache2 on $host is running"
echo "0"
else
echo "Apache2 on $host is not running"
echo "2"
fi
;;
*)
esac
done

My Bash script won't cache an item

I'm trying to use a Bash script I found and have slightly modified to automatically update the DNS settings on GoDaddy.
It sort of works, however I'm not getting the echo "no ip address, program exit" because I don't think on line 28 the cache file is being created. Would anybody be able to tell me what's going on? I'm using Raspbian. Many thanks in advance!
#/bin/bash
# This script is used to check and update your GoDaddy DNS server to the IP address of your current internet connection.
#
# Original PowerShell script by mfox: https://github.com/markafox/GoDaddy_Powershell_DDNS
# Ported to bash by sanctus
# Added AAAA record by Binny Chan
#
# Improved to take command line arguments and output information for log files by pollito
#
# First go to GoDaddy developer site to create a developer account and get your key and secret
#
# https://developer.godaddy.com/getstarted
#
# Be aware that there are 2 types of key and secret - one for the test server and one for the production server
# Get a key and secret for the production server
# Check an A record and a domain are both specified on the command line.
if [ $# -ne 2 ]; then
echo "usage: $0 type a_record domain_name"
echo "usage: $0 AAAA www my_domain"
exit 1
fi
# Set A record and domain to values specified by user
name=$1 # name of A record to update
domain=$2 # name of domain to update
cache=/tmp/.mcsync.$name.$domain.addr
[ -e $cache ] && old=`cat $cache`
# Modify the next two lines with your key and secret
key="key" # key for godaddy developer API
secret="secret" # secret for godaddy developer API
headers="Authorization: sso-key $key:$secret"
#echo $headers
# Get public ip address there are several websites that can do this.
ret=$(curl -s GET "http://ipinfo.io/json")
currentIp=$(echo $ret | grep -oE "\b([0-9]{1,3}\.){3}[0-9]{1,3}\b")
# Check empty ip address or not
if [ -z "$currentIp" ]; then
echo $name"."$domain": $(date): no ip address, program exit"
exit 1
fi
# Check cache ip, if matched, program exit
if [ "$old" = "$currentIp" ]; then
echo $name"."$domain": $(date): address unchanged, program exit $currentIp"
echo "IPs equal. Exiting..."
exit
else
echo $name"."$domain": $(date): currentIp:" $currentIp
fi
#Get dns ip
result=$(curl -s -k -X GET -H "$headers" \
"https://api.godaddy.com/v1/domains/$domain/records/A/$name")
dnsIp=$(echo $result | grep -oE "\b([0-9]{1,3}\.){3}[0-9]{1,3}\b")
echo $name"."$domain": $(date): dnsIp:" $dnsIp
# ip not match
if [ "$dnsIp" != $currentIp ];
then
echo $name"."$domain": $(date): IPs not equal. Updating."
request='{"data":"'$currentIp'","ttl":3600}'
#echo $request
nresult=$(curl -i -k -s -X PUT \
-H "$headers" \
-H "Content-Type: application/json" \
-d $request "https://api.godaddy.com/v1/domains/$domain/records/A/$name")
#echo $nresult
echo $name"."$domain": $(date): IPs not equal. Updated."
fi
No, the message is on line 44, which is written because $currentIp is empty, which is retrieved on line 39: reading the response of curl request to "http://ipinfo.io/json".
otherwise just remove the cache file
rm /tmp/.mcsync.$name.$domain.addr
where $name and $domain are replaced with first and second argument to script.

How to send test to a certain line using Bash Scripting

I know there are other posts on this but i cannot get any of them to work. My problem is that i want to create a script on my rpi to automatically change wifi networks and change eth0 between static and dhcp. It is not yet finished i am currently only working on the wireless part. But the script so far reads...
#!/bin/bash
ANS=''
ssid=''
psk=''
file='/etc/network/interfaces'
function wireless {
echo 'The wireless network '$ssid' has now been set up'
start
}
function ssid {
echo 'What is your Network SSID?'
echo -e '> \c'
read ssid
echo 'You entered '$ssid'. Is this correct? (y/n)'
echo -e '> \c'
read ANS
if [ $ANS = 'y' ]; then
psk
else
echo 'Please renter your SSID'
ssid
fi
}
function psk {
echo 'What is your Network PSK?'
echo -e '> \c'
read psk
echo 'You entered '$psk'. Is this correct? (y/n)'
echo -e '> \c'
read ANS
if [ $ANS = 'y' ]; then
wireless
else
echo 'Please renter your PSK'
psk
fi
}
function start {
echo 'What do you want to do?'
echo ''
echo 'Press w to set up wireless ssid and psk'
echo 'Press s to change eth0 to a static ip address'
echo 'Press d to change eth0 to a dhcp ip address'
echo ''
echo 'Or press ctrl+c to quit'
echo -e '> \c'
read ANS
if [ $ANS = 'w' ]; then
ssid
else
if [ $ANS = 's' ]; then
static
else
if [ $ANS = 'd' ]; then
dhcp
fi
fi
fi
}
#backup of /etc/network/interfaces
#auto lo
#iface lo inet loopback
#iface eth0 inet dhcp
#iface eth0 inet static
# address ###########
# netmask #############
# broadcast ###########
# gateway ##########
#
#allow-hotplug wlan0
#
#auto wlan0
#
#iface wlan0 inet dhcp
#wpa-ssid "Home Network"
#wpa-psk "psk"
start
exit 0
So thats all fine but in the function wireless i want to send the psk and the ssid to lines 15 and 16 of /etc/network/interfaces. Please could someone tell me the best method to do this by.
Thanks
You can perform automatic edits using sed like this:
sed -i "s/^wpa-ssid.*\$/wpa-ssid \"$ssid\"/" /etc/network/interfaces
This command matches any complete line beginning with wpa-ssid and replaces it with "wpa-ssid" followed by the contents of the $ssid variable. ^wpa-ssid.*\$ is the match pattern. ^ means the beginning of the line, .* means match anything, and \$ means the end of the line. wpa-ssid \"$ssid\"/ is what to replace it with.
The -i option means to edit the file, rather than print the result to standard out.
psk will work the same way.
You should consider having your script back up the file the first time it is run.
If I understand, you want to replace the quoted text in line 15 of /etc/network/interfaces with SSID text, and that of line 16 with PSK text. For example,
#wpa-ssid "Home Network"
#wpa-psk "psk"
might change to
#wpa-ssid "new-Network"
#wpa-psk "new-psk"
I don't see in your script code what variables you might have the new SSID and PSK names in, but if they were in variables called SSID and PSK, and FILE="/etc/network/interfaces", you could say:
sed -i "s/^#wpa-ssid.*/#wpa-ssid \"$SSID\"/; \
s/^#wpa-psk.*/#wpa-psk \"$PSK\"/" $FILE
The outer quotes are double-quotes to allow bash variable expansion. The inner double-quotes are back-slash quoted. Remove the back-slash at the end of the first line if you put the sed command on a single line. Also, when trying this out, make a copy of your interfaces file and set FILE to the name of the copy; run the sed command, then diff the copy with the original to check correct operation.

How can I read an IP address from the user in a bash script?

if [ "$1" == "-s" ]; then
echo "Connecting to host.."
scp root#IP_ADDRESS:/private/var/mobile/Library/SMS/sms.db /private/var/mobile/Media/BackupSMS
echo " "
exit
fi
I need to ask user for a IP-address, that will then be placed where IP_ADDRESS is above. I'm new to scripts, but I'm trying.
How would I do this?
Use the built in read command
read IP_ADDRESS
or, if you want a nice prompt:
read -p "Enter ip address: " IP_ADDRESS
and then add a $ to the scp line:
scp root#$IP_ADDRESS:/...
^

shell script + constant spaces between the IP to the aliases name

from my ksh script
.
echo $IP1 $ALIAS1 >> /etc/hosts
echo $IP2 $ALAIS2 >> /etc/hosts
echo $IP3 $ALIAS3 >> /etc/hosts
I get the hosts file as the following
10.10.10.10 node1_star
10.10.10.100 node_from_some_where
10.10.1.1 Node_HP_MACHINE
what the simple way to create the following hosts file view
in order to get constant spaces between the IP to the aliases name
as the follwoing:
(it could be by printf or by echo manipulation)
10.10.10.10 node1_star
10.10.10.100 node_from_some_where
10.10.1.1 Node_HP_MACHINE
printf is a powerful function that can do exactely what you want.
printf "%-20s %s\n" "$IP1" "$ALIAS1" >> /etc/hosts

Resources