Error when stacking SSH command arguments within a bash script using other scripts as variables - linux

I have a csv file called addresses.csv which looks like this,
node-1,xx.xxx.xx.xx,us-central-a
....
node-9,xxx.xx.xxx.xx,us-east1-a
I have a script below called 0run.sh,
#!/bin/bash
username='user'
persist="bash /home/${username}/Documents/scripts/disk/persistentDisk.sh"
first="bash /home/${username}/Documents/scripts/disk/firstAttach.sh"
while IFS=, read -r int ip <&3; do
if [ "$int" == "node-1" ]; then
--->ssh -i ~/.ssh/key -o StrictHostKeyChecking=no -l ${username} ${ip} "${persist}; ${first}"<---
else
ssh -i ~/.ssh/key -o StrictHostKeyChecking=no -l ${username} ${ip} "${first}"
fi
done 3<addresses.csv
The error occurs in the part of the code where I drew the arrows.
When it runs on node-1, instead of running ..persistentDisk.sh followed by ..firstAttach.sh, it only runs ..persistentDisk.sh and gives me the following error before it runs ..persistentDisk.
bash: /home/user/Documents/scripts/disk/firstAttach.sh: No such file or directory
The rest of the script runs completely fine. The only error occurs at this one part where it misses the 2nd script.
When I run the command like this it runs fine.
ssh -i ~/.ssh/key -o StrictHostKeyChecking=no -l ${username} ${ext} "${first}"
When I run it like this, it runs fine as well.
ssh -i ~/.ssh/key -o StrictHostKeyChecking=no -l user xxx.xx.xxx.xx "bash /home/${username}/Documents/scripts/disk/persistentDisk.sh; bash /home/${username}/Documents/scripts/disk/firstAttach.sh"
When I run the command like with a \ before the ; to escape it like this,
ssh -i ~/.ssh/key -o StrictHostKeyChecking=no -l ${username} ${ext} "${persist}\; ${first}"
I get the following error, and neither scripts run within the node-1 part of the code, but the rest of the code's else loops run fine.
bash: /home/user/Documents/scripts/disk/persistentDisk.sh;: No such file or directory
Why can't I stack the 2 commands within the if statement in the ssh using variables?

If I clearly understand: your real problem consist to leave STDIN free for interaction in target host!
About read and redirection
Try using:
#!/bin/bash
username='user'
persist="bash /home/${username}/Documents/scripts/disk/persistentDisk.sh"
first="bash /home/${username}/Documents/scripts/disk/firstAttach.sh"
while IFS=, read -r -u $list int ip foo; do
if [ "$int" == "node-1" ]; then
echo CMD... $ip, $persist
else
[ "$ip" ] && echo CMD... $ip, $first
fi
done {list}<addresses.csv
Tested, this èroduce:
CMD... xx.xxx.xx.xx, bash /home/user/Documents/scripts/disk/persistentDisk.sh
CMD... xxx.xx.xxx.xx, bash /home/user/Documents/scripts/disk/firstAttach.sh
-u flag to read, tell to use file descriptor ${list} instead of STDIN
foo is some useless variable used to prevent rest of line to be stored in $ip (xx.xxx.xx.xx,us-central-a in this case)
{list}</path/to/filename create a new variable by finding any free file descriptor.
About ssh (and redirection)
You could use:
#!/bin/bash
username='user'
persist="/home/${username}/Documents/scripts/disk/persistentDisk.sh"
first="/home/${username}/Documents/scripts/disk/firstAttach.sh"
while IFS=, read -r -u $list int ip foo; do
[ "$int" = "node-1" ] && cmd=persist || cmd=first
[ "$ip" ] && ssh -i ~/.ssh/key -t -o StrictHostKeyChecking=no \
-l ${username} ${ext} /bin/bash "${!cmd}"
done {list}<addresses.csv
By using this syntax, you will keep STDIN free for script running on target host.

Related

how to use value that is calculated inside ssh

I have linux script like below:
sshpass -p "pwd" ssh -tt user << 'EOF'
cd /directory
file=$(ls -1t | head -1)
exit
EOF
How to use the file parameter outside ssh. That is after EOF statement.
I think that you have to work with the output of the SSH command to capture it into a local variable.
This could be a viable solution (tried with obviously different parameters locally, OS Ubuntu 17.04):
CMD=`cat <<EOF
cd /directory
ls -1t | head -1
EOF`
FILE=`sshpass -p "pass" ssh -t user#host -o LogLevel=QUIET "$CMD"`
echo "$FILE"

bash script accessing ec2 instance

This script required an ip and the script or file that we have to run on the remote server i gave a file in which i have wrote commands like
touch /root/test
ls /root/test
this make the file but do not show and it is displaying an error
tcgetattr: Inappropriate ioctl for device
connection closed
How can I resolve this is there any suggestion ??
#!/bin/bash
# The private key used to identify this machine
IDENTITY_KEY=/home/admnew.pem
syntax()
{
echo "Syntax: Ec2.sh server_ip scriptFile]"
echo "For example: ./Ec2.sh server_ip scriptFile"
exit 1
}
if [ $# -ne 2 ]
then
echo not enough arguments
syntax
fi
echo "Running script $2 on $1"
ssh -t -t -i $IDENTITY_KEY ec2-user#$1 sudo -i 'bash -s' < $2
exit
exit
echo "Done"
Try:
ssh -t -t -i $IDENTITY_KEY ec2-user#$1 sudo -i 'bash -s' <<EOF
(
$(cat "$2")
)
EOF
e.g. wrap the script into (), e.g the:
touch /root/test
ls /root/test
should be
(
touch /root/test
ls /root/test
)

Bash script does not ssh all the entries of a csv file

I am trying to patch a bunch of CENT OS machines with the latest fix pack. I have the below bash script that takes csv file as a input which has the ip address and password for those machines.
The code works fine however, it would only work for the first row it does not seem to be working for the rest of the list as my output.txt only has the entry only for the first row host .
patch.sh
INPUT=hosts_test.cvs
OLDIFS=$IFS
IFS=,
[ ! -f $INPUT ] && { echo "$INPUT file not found"; exit 99; }
while read privateip password
do
sshpass -p$password ssh -t -o "StrictHostKeyChecking no" user123#$privateip "
hostname
hostname -I --all-ip-addresses
sudo yum -y update bash
env x='() { :;}; echo vulnerable' bash -c \"echo If you see the word vulnerable above, then you are vulnerable to shellshock\"
echo ""
exit
" >> output.txt
done < $INPUT
IFS=$OLDIFS
hosts_test.cvs
10.xxx.xx.219,abcd~qY1
10.xxx.xx.226,l4~abcdefg
10.xxx.xx.221,l4#abcdefgh
Terminal Output
Pseudo-terminal will not be allocated because stdin is not a terminal.
Add at the end of your sshpass command </dev/null.
Add Defaults:username !requiretty to your /etc/sudoers config
Get rid of -t from your ssh command
Optional, but recommended: set up public key auth so you don't have your passwords lying around in text files.
You can pass ssh another -t to force pty allocation:
ssh -t -t

shell script ssh command not working

I have a small list of servers, and I am trying to add a user on each of these servers. I can ssh individually to each server and run the command.
sudo /usr/sbin/useradd -c "Arun" -d /home/amurug -e 2014-12-12 -g users -u 1470 amurug
I wrote a script to loop through the list and run this command but I get some errors.
#!/bin/bash
read -p "Enter server list: " file
if [[ $file == *linux* ]]; then
for i in `cat $file`
do
echo "creating amurug on" $i
ssh $i sudo /usr/sbin/useradd -c "Arun" -d /home/amurug -e 2014-12-12 -g users -u 1470 amurug
echo "==============================================="
sleep 5
done
fi
When I run the script it does not execute the command.
creating amurug on svr102
Usage: useradd [options] LOGIN
Options:
What is wrong with my ssh crommand in my script?
Try this script:
#!/bin/bash
read -p "Enter server list: " file
if [[ "$file" == *linux* ]]; then
while read -r server
do
echo "creating amurug on" "$server"
ssh -t -t "$server" "sudo /usr/sbin/useradd -c Arun -d /home/amurug \
-e 2014-12-12 -g users -u 1470 amurug"
echo "==============================================="
sleep 5
done < "$file"
fi
As per man bash:
-t
Force pseudo-tty allocation. This can be used to execute arbitrary screen-based programs on a remote which can be very useful, e.g. when implementing menu services. Multiple -t options force tty allocation, even if ssh has no local tty.

pseudo-terminal error will not be allocated because stdin is not a terminal - sudo

There are other threads with this same topic but my issue is unique. I am running a bash script that has a function that sshes to a remote server and runs a sudo command on the remote server. I'm using the ssh -t option to avoid the requiretty issue. The offending line of code works fine as long as it's NOT being called from within the while loop. The while loop basically reads from a csv file on the local server and calls the checkAuthType function:
while read inputline
do
ARRAY=(`echo $inputline | tr ',' ' '`)
HOSTNAME=${ARRAY[0]}
OS_TYPE=${ARRAY[1]}
checkAuthType $HOSTNAME $OS_TYPE
<more irrelevant code>
done < configfile.csv
This is the function that sits at the top of the script (outside of any while loops):
function checkAuthType()
{
if [ $2 == linux ]; then
LINE=`ssh -t $1 'sudo grep "PasswordAuthentication" /etc/ssh/sshd_config | grep -v "yes\|Yes\|#"'`
fi
if [ $2 == unix ]; then
LINE=`ssh -n $1 'grep "PasswordAuthentication" /usr/local/etc/sshd_config | grep -v "yes\|Yes\|#"'`
fi
<more irrelevant code>
}
So, the offending line is the line that has the sudo command within the function. I can change the command to something simple like "sudo ls -l" and I will still get the "stdin is not a terminal" error. I've also tried "ssh -t -t" but to no avail. But if I call the checkAuthType function from outside of the while loop, it works fine. What is it about the while loop that changes the terminal and how do I fix it? Thank you one thousand times in advance.
Another option to try to get around the problem would be to redirect the file to a different file descriptor and force read to read from it instead.
while read inputline <&3
do
ARRAY=(`echo $inputline | tr ',' ' '`)
HOSTNAME=${ARRAY[0]}
OS_TYPE=${ARRAY[1]}
checkAuthType $HOSTNAME $OS_TYPE
<more irrelevant code>
done 3< configfile.csv
I am guessing you are testing with linux. You should try add the -n flag to your (linux) ssh command to avoid having ssh read from stdin - as it normally reads from stdin the while loop is feeding it your csv.
UPDATE
You should (usually) use the -n flag when scripting with SSH, and the flag is typically needed for 'expected behavior' when using a while read-loop. It does not seem to be the main issue here, though.
There are probably other solutions to this, but you could try adding another -t flag to force pseudo-tty allocation when stdin is not a terminal:
ssh -n -t -t
BroSlow's approach with a different file descriptor seems to work! Since the read command reads from fd 3 and not stdin,
ssh and hence sudo still have or get a tty/pty as stdin.
# simple test case
while read line <&3; do
sudo -k
echo "$line"
ssh -t localhost 'sudo ls -ld /'
done 3<&- 3< <(echo 1; sleep 3; echo 2; sleep 3)

Resources