BASH: ssh access variable result on remote host - bash

How do I make a variable accessible on a remote computer via ssh?
I have a bash array containing n IP addresses for this specific instance I want to send the "result" of the first element in the array to the remote machine for further use.
#!/bin/bash
servers=(192.168.130.252 10.10.10.10 12.12.12.12)
echo "Before ssh: ${servers[0]}"
ssh ubuntu#"${servers[0]}" /bin/bash<<"EOF"
echo "$(hostname -I | awk '{print $1}')"
echo "After ssh: ${servers[0]}"
# MORE COMMAND HERE
EOF
exit 0
#Output
Before ssh: 192.168.130.252
192.168.130.252
After ssh:

Because you have used quotes in "EOF", ${servers[0]} gets expanded in remote shell, so to an empty string as array servers is not defined.
One way around is :
#!/bin/bash
servers=(192.168.130.252 10.10.10.10 12.12.12.12)
echo "Before ssh: ${servers[0]}"
ssh ubuntu#"${servers[0]}" CURRENT_HOST="${servers[0]}" /bin/bash<<"EOF"
echo "$(hostname -I | awk '{print $1}')"
echo "After ssh: $CURRENT_HOST"
# MORE COMMAND HERE
EOF
exit 0
Just found a way to send the whole array to remote shell:
#!/bin/bash
servers=(192.168.130.252 10.10.10.10 12.12.12.12)
echo "Before ssh: ${servers[0]}"
{ declare -p servers
cat << "EOF"
echo "$(hostname -I | awk '{print $1}')"
echo "After ssh: ${servers[0]}"
# MORE COMMAND HERE
EOF
} | ssh ubuntu#"${servers[0]}" /bin/bash

Related

How to assign a color to a variable within a bash function

I have following script where i want to to print the command Variable SMB into the RED colour within a bash function but that's not working.
Below is the Script:
Script:
#!/bin/bash
read -rsp $'Please Enter password below: ' SSHPASS
echo -n ""
export SSHPASS
NC='\033[0m'
RED='\033[0;31m'
remote_connect() {
target_host=$1
sshpass -e ssh -q "${target_host}" "true" -o StrictHostKeyChecking=no -o ConnectTimeout=60 2>>/dev/null
if [[ $? -eq 0 ]]
then
SMB=$(sshpass -e ssh -q -t "$target_host" "sudo smbstatus |grep ^Samba")
printf "%-35s %15s\n" "$target_host" "${RED}${SMB}${NC}"
else
printf "%-35s %15s\n" "$target_host" "Unable to get the ssh connection"
fi
} 2>/dev/null
export -f remote_connect
< host_list xargs -P5 -n1 -d'\n' bash -c 'remote_connect "$#"' --
Result:
tdi1990.colx.fox.com \033[0;31m Samba version 4.9.1 \033[0m \n
tdi1856.colx.fox.com \033[0;31m Samba version 4.9.1 \033[0m \n
tdi1993.colx.fox.com \033[0;31m Samba version 4.9.1 \033[0m \n
If i use echo like below it works, but then the lifet and right justify as i am trying with print that's not possible with echo.
echo -e "$target_host" "${RED}${SMB}${NC}"
Expected:
Second column that is Samba version 4.9.1 should be printed in Red color.
This should achieve what you expected :
NC=$'\033[0m'
RED=$'\033[0;31m'

Extracting specific nmap output in bash

I'm getting following nmap output from a scan:
PORT STATE SERVICE
113/tcp closed ident
443/tcp open https
5060/tcp open sip
I want to extract only open ports and save them into a variable while my script progress is below:
#!/bin/bash
echo Please enter your IP/domain address for nmap vulnerability scanning:
read IP
echo Your results against $ip will be output in sometime
nmap -sS -oG output.txt $ip
Grep them
nmap -sS -oG output.txt $ip | grep open
To store in var
open_ports=$(nmap -sS -oG output.txt $ip | grep open)
open_ports=${open_ports//[^0-9]/ } # remove text
Convert to an array
open_ports_arr=( $open_ports )
Here is how you can filter and extract open ports using awk and read the results into a bash array:
#!/usr/bin/env bash
# Read prompt ip address
read \
-p 'Please enter your IP/domain address for nmap vulnerability scanning: ' \
-r ip
# Print format info to user
printf 'Your results against %s will be output in sometime.\n' "$ip"
# Read the output of the nmap | awk commands into the ports array
IFS=$'\n' read -r -d '' -a ports < <(
# Pipe the result of nmap to awk for processing
nmap -sS -oG output.txt "$ip" |
awk -F'/' '
/[[:space:]]+open[[:space:]]+/{
p[$1]++
}
END{
for (k in p)
print k
}'
)
# If the resulting pors array is not empty iterate print format its content
if [ ${#ports[#]} -gt 0 ]; then
printf 'List of open ports on host IP: %s\n' "$ip"
for p in "${ports[#]}"; do
printf '%d\n' "$p"
done
fi

I am not able to Ping IPs from my indexed array but works with an associative array

I am trying to iterate IPs which are read from a csv to an array as a kind of monitoring solution. I have the ips in a indexed array and want to pass the ips to the ping command but its not working.
#!/bin/bash
datei=hosts.csv
length=$(cat $datei | wc -l)
for (( i=1; i<=$length; i++ ))
do
ips[$i]=$(cut -d ';' -f2 $datei | awk 'NR=='$i'')
hosts[$i]=$(cut -d ';' -f1 $datei | awk 'NR=='$i'')
done
servers=( "1.1.1.1" "8.8.4.4" "8.8.8.8" "4.4.4.4")
for i in ${ips[#]} #Here i change the array i want to iterate
do
echo $i
ping -c 1 $i > /dev/null
if [ $? -ne 0 ]; then
echo "Server down"
else
echo "Server alive"
fi
done
Interesting is that if I iterate the server array instead of the ips array it works. The ips array seems from data fine if printed.
The output if I use the servers array:
1.1.1.1
Server alive
8.8.4.4
Server alive
8.8.8.8
Server alive
4.4.4.4
Server down
and if I use the ips array
1.1.1.1
: Name or service not known
Server down
8.8.4.4
: Name or service not known
Server down
8.8.8.8
: Name or service not known
Server down
4.4.4.4
: Name or service not known
Server down
Output from cat hosts.csv
test;1.1.1.1
test;8.8.4.4
test;8.8.8.8
test;4.4.4.4
First column is for Hostnames and the second column for the IPs in v4.
I am on Ubuntu 20.4.1 LTS
Fixed multiple issues with your code:
Reading of hosts.csv into arrays.
Testing the ping result.
hosts.csv:
one.one.one.one;1.1.1.1
dns.google;8.8.4.4
dns.google;8.8.8.8
invalid.invalid;4.4.4.4
Working commented in code:
#!/usr/bin/env bash
datei=hosts.csv
# Initialize empty arrays
hosts=()
ips=()
# Iterate reading host and ip in line records using ; as field delimiter
while IFS=\; read -r host ip _; do
hosts+=("$host") # Add to the hosts array
ips+=("$ip") # Add to the ips array
done <"$datei" # From this file
# Iterate the index of the ips array
for i in "${!ips[#]}"; do
# Display currently processed host and ip
printf 'Pinging host %s with IP %s\n' "${hosts[i]}" "${ips[i]}"
# Test the result of pinging the IP address
if ping -nc 1 "${ips[i]}" >/dev/null 2>&1; then
echo "Server alive"
else
echo "Server down"
fi
done
You can read into an array from stdin using readarray and so combining this with awk to parse the Host.csv file:
readarray -t ips <<< "$(awk -F\; '{ print $2 }' $date1)"
readarray -t hosts <<< "$(awk -F\; '{ print $1 }' $date1)"

ssh when invoked with variables form while loop not working

I am running into an issue where I am comparing two files (alert.txt and env.txt) and based on common value, I am pulling complete line data from env.txt based on matching entry. I am reading these values into while loop and then invoking a function as follows. the ssh call is not working and also the while loop inside start_admin not working
#!/bin/bash
start_admin()
{
ssh -n -f $user#$host "sh -c 'cd $domain; ./script.sh > /dev/null 2>&1'"
while !(netstat -na | grep -E $host:$port|grep -E LISTEN) 2>/dev/null
sleep 30
do
echo "waiting"
done
echo "started"
}
grep -Ff alert.txt env.txt | (while IFS=" " read -r r1 r2 r3 r4 r5
do
user=$r2
host=$r3
domain=$r4
port=$r5
done
start_admin $user $host $domain $port
)
and contents of alert.txt is:
env2
env3
and that of env.txt is :
env1 user1 host1 /app/domain1/ port1
env2 user2 host2 /app/domain2/ port2
env3 user3 host3 /app/domain3/ port3
I could solve this with multiple if else loops, but that is not a desired solution, please guide me in right direction as to what is missing ?
Use join instead of grep here to avoid false positives
Because your while read loop completes before you run start_admin, you only launch it once (done should be AFTER start_admin)
In start_admin, don't use $user, $host and so on, use $1, $2 (or use them but don't pass them as parameters when calling the function)
I'm not sure exactly what you try to achieve, but here is a revised version already.
#!/bin/bash
start_admin()
{
sanitized_domain=${domain//'"'/'\"'}
ssh -n -f "$user#$host" "sh -c 'cd \"$sanitized_domain\"; ./script.sh >/dev/null 2>&1'"
while ! netstat -na | grep -q " $host:$port .*LISTEN"; do
echo waiting
sleep 30
done
echo started
}
join alert.txt env.txt | while IFS=' ' read -r env user host domain port; do
start_admin
done
)

trouble executing SSH remote ash script on ESXI Host

I have two servers: Linux shell (192.168.1.11) and ESXI host ash shell (192.168.1.12).
Desired outcome:
Local testsuspend.sh scp uploads suspendvm.sh to remote ESXI server and executes on ESXI. When finished testsuspend.sh continues and exits.
Script testsuspend.sh on .11 uploads an ash script (suspendvm.sh) to ESXi host .12, should execute it and wait until it's finished,then finish testsuspend.sh.
On Linux I want to remote execute a script suspendvm.sh from another script testsuspend.sh to suspend all VMs and put ESXI host in maintenance mode.
When I execute the testsuspend.sh on Linux it stops on executing suspendvm.sh via SSH. If I execute the suspend script sustendvm.sh on the ESXI host directly it works.
File after copy on ESXI:
-rwxr-xr-x 1 root root 1260 Apr 16 07:06 suspendvm.sh
Would you have an idea on what I need to do here to get the ssh remote script to execute properly on the ESXi host and the local script to wait until remote is finished?
... So I found that if I run this in the testsuspend.sh it works:
cat suspendVM.sh | ssh -T $user#$host
Why does this work but not the copy and execute?
Local script 192.168.1.11, testsuspend.sh should execute suspenvm.sh remotely:
#!/bin/sh
user="root"
host="192.168.1.120"
scp suspendvm.sh $user#$host:/tmp
echo "copy suspend script"
ssh $user#$host 'sh -s /tmp/suspendvm.sh' &
exit
Remote script 192.168.1.12, suspendvm.sh works when I execute on ESXI host .12):
#!/bin/sh
RUNNING=0
VMS=`vim-cmd vmsvc/getallvms | grep -v Vmid | awk '{print $1}'`
for VM in $VMS ; do
# echo "Probing VM with id: $VM."
PWR=`vim-cmd vmsvc/power.getstate $VM | grep -v "Retrieved runtime info"`
name=`vim-cmd vmsvc/get.config $VM | grep -i "name =" | awk '{print $3}' | head -1 | awk -F'"' '{print $2}'
echo "VM with id $VM has power state $PWR (name = $name)."
if [ "$PWR" == "Powered on" ] ; then
RUNNING=1
echo "Powered on VM with id $VM and name: $name"
echo "Suspending VM with id $VM and name: $name"
vim-cmd vmsvc/power.suspend $VM > /dev/null &
fi
done
while true ; do
if [ $RUNNING -eq 0 ] ; then
echo "Gone..."
break
echo "Powered on VM with id $VM and name: $name"
echo "Suspending VM with id $VM and name: $name"
vim-cmd vmsvc/power.suspend $VM > /dev/null &
fi
done
while true ; do
if [ $RUNNING -eq 0 ] ; then
echo "Gone..."
break
fi
RUNNING=0
for VM in $VMS ; do
PWR=`vim-cmd vmsvc/power.getstate $VM | grep -v "Retrieved runtime info"`
if [ "$PWR" == "Powered on" ] ; then
name=`vim-cmd vmsvc/get.config $VM | grep -i "name =" | awk '{print $3}' | head -1 | awk -F'"' '{$
echo "Waiting for id $VM and name: $name..."
RUNNING=1
fi
done
sleep 1
esxcli system maintenanceMode set --enable true
done
Remote script #2 that should do the same via esxicli, it also works when I execute it on .12 but not via ssh from .11:
#! /bin/ash
#test2
rm -f listid
touch listid
######## Listing the running vms################
esxcli vm process list |grep -v "^\s.*"| grep -v "^$" > list
######## If you want to reuse list for later use #######
####### put the file in a datastore, else it ##########
#######gonna be erease on next reboot ##########
####### Command look like this: ###############
## esxcli vm process list |grep -v "^\s.*"| grep -v "^$" > /vmfs/volumes/tmp/list
########## cleaning the id.s file by keeping only the id
for name in `cat list`;do
########## Dont forget to change the path if #######
########## you choose to put it in a datastore #####
####### put the file in a datastore, else it ##########
#######gonna be erease on next reboot ##########
####### Command look like this: ###############
## esxcli vm process list |grep -v "^\s.*"| grep -v "^$" > /vmfs/volumes/tmp/list
########## cleaning the id.s file by keeping only the id
for name in `cat list`;do
########## Dont forget to change the path if #######
########## you choose to put it in a datastore #####
## Example: for name in `cat /vmfs/volumes/yourDatastore/list`;do
vim-cmd vmsvc/getallvms | grep $name | grep vmx | grep -v "^$" | awk '{print $1}'>> listid
done
for id in `cat listid`;do
###### suspending vms##########
echo "Suspending the running machines"
vim-cmd vmsvc/power.suspend $id
## Example: for name in `cat /vmfs/volumes/yourDatastore/list`;do
vim-cmd vmsvc/getallvms | grep $name | grep vmx | grep -v "^$" | awk '{print $1}'>> listid
done
for id in `cat listid`;do
###### suspending vms##########
echo "Suspending the running machines"
vim-cmd vmsvc/power.suspend $id
done
echo "done."
echo "shutting down the host now.."
#/bin/poweroff
vim-cmd hostsvc/maintenance_mode_enter
#excli system maintenanceMode set --enable true
#done

Resources