bash script stuck at the end of a for loop - bash

I'm trying to deploy $DM_COUNT docker-machines through a script, and write new network configuration to the nodes. The script works fine until the end of the loop and then gets stuck
The script is called from this script:
#!/bin/bash
set -x
PS4='$LINENO: '
net="10.17.65."
The loop starts properly
for i in $(seq 1 $DM_COUNT); do
(
name="$PREFIX$DEPLOYMENTNAME$i"
echo "$name"
if [ -z "$DM_NAMES" ]
then
export DM_NAMES=$name
else
export DM_NAMES=$DM_NAMES:$name
fi
ip="$net$((4 + i))"
mkdir -p ~/.ssh && touch $_/config &&
tee -a $_ << EOF
Host $name
Hostname $ip
User docker
IdentityFile ~/.docker/machine/machines/$name/id_rsa
EOF
docker-machine create $name\
--driver vmwarevsphere \
--vmwarevsphere-cpu-count 4 \
--vmwarevsphere-datastore datastore1 \
--vmwarevsphere-disk-size 60000 \
--vmwarevsphere-memory-size 2048 \
--vmwarevsphere-network 'VM\ Network' \
--vmwarevsphere-vcenter 10.17.6.218 \
--vmwarevsphere-password a \
--vmwarevsphere-username root
docker-machine restart "$name"
docker-machine regenerate-certs -f "$name"
echo 'Done provisioning ' "$name"
docker-machine scp -r /certs/ "$name":/root/certs/
docker-machine ssh "$name" sudo mkdir /var/lib/boot2docker/certs
docker-machine ssh "$name" sudo cp /root/certs/*.crt /var/lib/boot2docker/certs/
echo 'Done copying self-signed certificates'
echo "
# configure eht1 (czlocal1)
sudo ip addr flush dev eth1
sudo ip route del default
sudo ip route add default via 192.168.1.254
# configure eth2 (czlocal2)
sudo ip addr flush dev eth0
sudo ip route add default via 192.168.2.254
# configure eth3 (czlocaldhcp)
sudo ip addr flush dev eth0
# configure eth0 (mgmt)
sudo ip addr flush dev eth0
ip addr add 10.17.65.10$i/24 dev eth0
ip route add 10.17.36.0/24 via 10.17.65.1 dev eth0
ip route add 10.17.33.0/24 via 10.17.65.1 dev eth0
# configure eth2 (czlocal2)
sudo ip addr flush dev eth2
ip addr add 192.168.2.$i/24
# configure eth3 (czlocaldhcp)
sudo ip addr flush dev eth3
" | docker-machine ssh "$name" "sudo tee /var/lib/boot2docker/bootsync.sh"
echo "
sudo ip route del default
sudo ip route add default via 192.168.$1.254
" | docker-machine ssh "$name" "sudo tee ~/switch_default_gateway.sh"
echo "
alias local1='ip route del default && ip route add default via 192.168.1.254'
alias local2='ip route del default && ip route add default via 192.168.2.254'
alias dhcp='ip route del default && ip route add default via 172.0.0.254'
" | docker-machine ssh "$name" "sudo tee -a ~/.bashrc > /dev/null"
echo 'Done writing scripts'
docker-machine ssh "$name" "sudo chmod +x /var/lib/boot2docker/bootsync.sh"
docker-machine ssh "$name" "sudo chmod +x ~/switch_default_gateway.sh"
docker-machine ssh "$name" "source ~/.bashrc"
jq '.Driver.IPAddress = $newVal' --arg newVal '10.17.65.10'$i ~/.docker/machine/machines/"$name"/config.json > tmp.$$.json && mv tmp.$$.json ~/.docker/machine/machines/"$name"/config.json
echo 'Done deploying docker machines'
) &
done
Everything until this point executes fine, then the script is stuck. If I provide any input on the shell it exits.
tee -a ~/.ssh/config << EOF
Host *
StrictHostKeyChecking no
EOF
The last part never gets executed

Are you sure you don't have a 'non breakable space' (https://en.wikipedia.org/wiki/Non-breaking_space) between your << and EOF?
Anyway, your initial script, and the indicated lines at the end of your question is not the same (the one involving tee command), can you update your question to fit the final version of your script?

Related

How to redirect output of an entire shell script within the script itself? ... with a twist

I have seen this (and I upvoted it), but it falls a bit short from my needs because:
I have to I need to give on-terminal feedback (that is easy, just | tee /dev/tty)
I have to get input from users in several ways:
read -p 'prompt: ' var
select yn in "Yes" "No"; do ...
git clone from private repository asking user/pass
How can I do this (especially the select stuff)?
My current test setup (cut down to size) is:
#/bin/bash
set -e
set -x
{
if lxc list | grep container
then
:
else
lxc launch images:ubuntu/20.04 container
echo 'waiting for networking to be up-and-running...' | tee /dev/tty
sleep 5
echo 'installing base system...' | tee /dev/tty
lxc exec container -- apt update
lxc exec container -- apt install -y git
echo "install documentation processor? " | tee /dev/tty
select yn in "Yes" "No"
do
if [ $yn == "Yes" ]
then
echo 'installing documentation processor...' | tee /dev/tty
lxc exec container -- apt install -y wget
lxc exec container -- wget https://github.com/plantuml/plantuml/releases/download/v1.2022.12/plantuml-1.2022.12.jar -O /usr/local/bin/plantuml.jar
fi
break
done
read -p 'enter your EMAIL address: ' email | tee /dev/tty
lxc exec container --user 1000 --group 1000 --cwd /home/ubuntu --env HOME=/home/ubuntu -- git config --global user.email "$email"
read -p 'enter your FULL NAME: ' name | tee /dev/tty
lxc exec container --user 1000 --group 1000 --cwd /home/ubuntu --env HOME=/home/ubuntu -- git config --global user.name "$name"
lxc exec container --user 1000 --group 1000 --cwd /home/ubuntu --env HOME=/home/ubuntu -- git config --global credential.helper store
echo 'cloning repository...' | tee /dev/tty
lxc exec container --user 1000 --group 1000 --cwd /home/ubuntu --env HOME=/home/ubuntu -- git clone git#github.com:gabime/spdlog.git
echo "enable audio in container? " | tee /dev/tty
select yn in "Yes" "No"
do
if [ $yn == "Yes" ]
then
for dev in $(find /dev/snd -type c)
do
lxc config device add container snd_$(basename $dev) unix-char source=$dev path=$dev gid=1000
lxc exec container -- apt install -y alsa-utils
done
fi
break
done
fi
} >lxd_build.log 2>&1
This has all said defects:
read -p prompts are not seen on terminal (but are in log file)
select yn in "Yes" "No" prompts are not seen on terminal (but are in log file); this is unsurprising as select doesn't accept redirection.
git clone prompt for user/pass are not seen on terminal.
How can I fix this?
read -p and select both output their prompts to standard error. Make sure you're capturing the right stream if you want to copy their prompts to both the terminal and a file. For example:
read -p 'enter your EMAIL address: ' email | tee /dev/tty # prompt doesn't get duplicated
read -p 'enter your EMAIL address: ' email 2>&1 | tee /dev/tty # prompt does get duplicated
###
# Note: These cases might get a bit annoying because the redirection
# applies to both the prompt and everything inside the select statement
# You may have to do some additional redirection inside the select
# statement to make everything work exactly the way you want
###
select yn in "Yes" "No" ; do
break
done | tee /dev/tty # prompt does not get duplicated
select yn in "Yes" "No" ; do
break
done 2>&1 | tee /dev/tty # prompt does get duplicated
git clone might be more complicated. If it's using something like OpenSSH under the covers to perform ssh operations then it could be writing directly to the TTY so you can't redirect its prompts just by redirecting standard out or standard error. You may have to dive into tools like expect to capture the password prompts and write them somewhere else.

How can I enter a directory (using cd command) and execute a specific file in a shell script?

I need to connect redis server from my local machine . I have installed redis on my machine under the path: /Users/huangkunlun/Work/soft/redis/redis-6.0.10
If I enter the redis installation and run the command like following from my terminal,it will be successful.
cd /Users/huangkunlun/Work/soft/redis/redis-6.0.10/src
redis-cli -h reids-host-server -p 6379 -a psw
but if i run the previous two command in shell script file,I got error displaying command redis-cli can not be found.
so the question is how can I enter a specific dir and execute the specific file under that dir from a shell script ?
the shell script file is like following:
#!/bin/bash
REDIS_SRC_DIR=/Users/huangkunlun/Work/soft/redis/redis-6.0.10/src
HOST_TEST=redis-test-in.shantaijk.cn
HOST_DEV=r-uf61x52g8b0cketmk7.redis.rds.aliyuncs.com
env=$1
echo "environment is ${env}"
cd ${REDIS_SRC_DIR}
echo "cd redis directory $(pwd)"
if [[ ${env} == "test" ]]; then
#/Users/huangkunlun/Work/soft/redis/redis-6.0.10/src/redis-cli -h ${HOST_TEST} -p 6379 -a Cloudhis1234
redis-6.0.10/src/redis-cli -h ${HOST_TEST} -p 6379 -a Cloudhis1234
elif [[ ${env} == "dev" ]]; then
#/Users/huangkunlun/Work/soft/redis/redis-6.0.10/src/redis-cli -h ${HOST_DEV} -p 6379 -a Cloudhis1234
redis-cli -h ${HOST_DEV} -p 6379 -a Cloudhis1234
else
echo "no env args is specified, exit..."
fi

Automate Password on Bastion Host?

My New Job requires me to gather some info from thousands of servers. However they have no sshkey setup. Everything is linked to LDAP password.
Setup is
{ Mac using ITerm2 } -->ssh with LDAP+2fA --> Bastion Host --> Connect to all servers but only with LDAP Password.
I dont want to keep typing LDAP passwords for each host I am trying to login. I am non-privilege user on Bastion Host. I cannot Install anything on Bastion like sshpass,expect,plink,
How to Automate entering password with below script with ssh options either in the script itself or Can we use Iterm to autofill when it prompts for password ?
#!/bin/bash
inFile=$1
user="zaib"
ssh_options="-o ConnectTimeout=5 -o ConnectionAttempts=1 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"
read -r -d "" commands << EOF
#My Commands Here
uname -a;
netstat -rn;
EOF
log="remote_cmd_$inFile"
((c=1))
for srv in $(cat $inFile | awk -F, '{print $1}'); do
echo -n "$c: $srv " | tee -a $log
nohup ssh -qtt $ssh_options $user#$srv "sudo --bash -c '$commands'" 2>&1 | tee -a $log
((c=$c+1))
done

How do I make a Bash script run a command in the background in another Terminal window?

I'm new to bash script and I need to make a script that runs the following commands:
service apache2 start
airmon-ng start wlan0
airbase-ng -e FREEINTERNET -c 1 -P wlan0mon
ifconfig at0 192.168.1.129 netmask 255.255.255.128
route add -net 192.168.1.128 netmask 255.255.255.128 gw 192.168.1.129
echo 1 > /proc/sys/net/ipv4/ip_forward
iptables --table nat --append POSTROUTING --out-interface wlan1 -j MASQUERADE
iptables --append FORWARD --in-interface at0 -j ACCEPT
iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination 192.168.0.4:80
iptables -t nat -A PREROUTING -p tcp --destination-port 443 -j REDIRECT --to-port 80
iptables -t nat -A POSTROUTING -j MASQUERADE
dhcpd -cf /etc/dhcpd.conf -pf /var/run/dhcpd.pid at0
service isc-dhcp-server start
My big doubt is how to make the script open the airbase-ng -e FREEINTERNET -c 1 -P wlan0mon command in a different terminal and keep executing both airbase and the remaining commands. I’m using Kali 64-bit with GNOME.
You can run something in the background by suffixing it with &. If you want to run something in a new GNOME Terminal window, you can do so with gnome-terminal -e. Putting those together, to run your airbase-ng command in a new GNOME Terminal window while letting the rest of your script continue to run:
# …
airmon-ng start wlan0
gnome-terminal -e 'airbase-ng -e FREEINTERNET -c 1 -P wlan0mon' &
ifconfig at0 192.168.1.129 netmask 255.255.255.128
# …

Bash script failing [duplicate]

This question already has answers here:
write a shell script to ssh to a remote machine and execute commands
(10 answers)
Closed 9 years ago.
I'm writing a script which purpose is to connect to a number of servers and create an account. The "core" is:
ssh user#ip
sudo su -
useradd -m -p 123 $1
if [ $? -eq 0 ]; then
echo "$1 successfully created on ip."
fi
chage -d 0 $1
chown -R $1 /home/$1
exit #exit root
exit #exit the server
I have established a private-public key relationship between the servers in order to be able to perform the ssh without being prompted for the password, however, when I run the script it does the ssh but then doesn't perform the next commands on the target machine. Instead, when manually exiting from the target server, I see that those commands were executed (or better said, tried to be executed) on the local machine.
So there should be no asking password when run both ssh and sudo command
ssh user#ip bash -c "'
sudo su -
useradd -m -p 123 $1
if [ $? -eq 0 ]; then
echo "$1 successfully created on ip."
fi
chage -d 0 $1
chown -R $1 /home/$1
exit #exit root
exit #exit the server
'"
If you are planning to sudo why don't you just ssh as root: root#ip? Just do:
ssh root#ip 'command1; command2; command3'
In your case if you want to be sure they are all successfull in order to proceed:
ssh root#ip 'USER=someUser; useradd -m -p 123 $USER && chage -d 0 $USER && chown -R $USER /home/$USER'
EDIT:
If the root access is not alowed if would do the following:
Create the script with the commands you want to execute on the remote machine, for instance script.sh:
#!/bin/bash
USER=someUser
useradd -m -p 123 $USER && chage -d 0 $USER && chown -R $USER /home/$USER
Copy the script to the remote machine:
scp script.sh user#ip:/destination/dir
Invoke it remotely:
ssh user#ip 'sudo /destination/dir/script.sh'
EDIT2:
Other option without creating any files:
ssh user#ip "sudo bash -c 'USER=someUser && useradd -m -p 123 $USER && chage -d 0 $USER && chown -R $USER /home/$USER'"
It won't work this way. You shoudl do it like:
ssh user#ip 'yourcommands ; listed ; etc.' or
copy the script you want to execute on the servers via scp /your/scriptname user#ip:/tmp/ then execute it ssh user#ip 'sh /tmp/yourscriptname'
But you are starting another script when starting sudo.
Now you have (at least) two options:
ssh user#ip 'sudo -s -- "yourcommands ; listed ; etc."' or
copy the part after the sudo to a different script, then:
ssh user#ip 'sudo -s -- "sh differentscript"'`

Resources