0

I am trying to run a for loop which looks something like this

cat  all_data |
  awk '{print $1 " "$2" " $3}'  |
  while read inst type serial ; do
    echo $inst
    if [ `echo ${inst} | cut -d '-' -f2` = H3 ]; then
      ssh  -t  username@hostname3 "sudo ls"
    elif [ `echo ${inst} | cut -d '-' -f2` = H2 ] ; then
      ssh  -t  username@hostname2 "sudo ls"
    elif [ `echo ${inst} | cut -d '-' -f2` = H1 ]; then
      ssh  -t  username@hostname1 "sudo ls"
    fi
  done

I am not able to run the ssh -t part,it says psuedo terminal will not be allocated becasued stdin is not a terminal sudo: no tty present and no askpass program specified I have tried with -t -t and -n, no luck. I cant edit the visudo file from the host i am running this command from.

Edit

$ cat all_data
ABC-DIF2    DELL-800    60999
ABC-DIF3    HP-DL340    J0777
ABC-DIF4    DELL-800    P0087
.
.
.

The all_data contains 1000's of the similar entries. What i am trying to do it as follows. 60999,J0777... are the entities on which i need to run commands on.

So i am trying to read each line, split up and check what is the DIF number corresponding to the entity.

eg If i read DIF2, it means that i need to ssh into hostname2 and run the command to get data on the 60999

If if i read DIF3, it means for the entity J0777 can only be run from hostname3.

  • 1
    The error message is correct. at the point where ssh is being run, stdin is not a tty, it is a pipe from awk. try ssh -o Batchmode=yes instead of ssh -t. BTW, your script repeats itself a lot. e.g. instead of running the echo | cut three times, run it once and assign the output to a variable, then use the variable in the test. e.g. inst2="$(echo "$inst" | cut -d- -f2)" and if [ "$inst2" = H3 ] ; then .... The if/elif/elif is also redundant if you're using bash, it can be done in one line [[ "$inst2" =~ H3|H2|1 ]] && ssh ... – cas Jul 23 '17 at 01:01
  • 1
    finally, you probably need to setup key-based login so that ssh doesn't prompt for a password. add your public key from the local machine to ~username/.ssh/authorized_hosts on the remote system. or run ssh-agent – cas Jul 23 '17 at 01:04
  • Thanks for the input, tried the bactchmode=yes, it is still complaining about sudo: no tty present and no askpass program specified – coolguy6764 Jul 23 '17 at 01:52
  • can you edit your question and add a sample of the all_data file, and a description of what it is you're actually trying to do? My guess is that what you want is probably quite simple but you're over-complicating the procedure. BTW, i just noticed that "H2" triggers an ssh to a different hostname (i initially thought they were all the same). – cas Jul 23 '17 at 02:08
  • Hi Case , Just edited the same and added, – coolguy6764 Jul 23 '17 at 02:49
  • Is the user allowed to sudo with no password? – Deathgrip Jul 23 '17 at 03:14
  • no, we have to put the password it, that is the problem , cant use ssh keys – coolguy6764 Jul 23 '17 at 03:34
  • 1
    how do you get from DIF2 to hostname2? is there some simple mapping (e.g. the same basic hostname with a numeric suffix) or is there some lookup table? Do you run the same command on each remote host? Is this a small part of a much bigger script or is it the bulk of the script? (given that the sysadmin of the remote system doesn't understand how ssh security works or how to configure sudo properly, i think that an expect script - or, better yet, a perl Net::SSH or python pexpect script - is the right tool for the job here. – cas Jul 23 '17 at 03:42
  • Like the idea of using Net::SSH and Perl. Me, I'd use Ansible. – Deathgrip Jul 23 '17 at 03:57
  • Extremely insecure change "sudo ls" to "echo PASSWORD | sudo -S ls". Where PASSWORD is username's password on the host for sudo. Even in a Perl or Python script, you would likely need the password for sudo in cleartext in the script. – Deathgrip Jul 23 '17 at 04:10

1 Answers1

1

Asides: your (example?) cat and awk are useless, and you don't need the repeated echo|cut and tests.

After clarification that you need to type the password(s) for the remote sudos, you need to both let ssh use the terminal input and specify -t so it forwards that input as a PTY. This is basically a dupe of SSH causes while loop to stop although you didn't reach the same symptom.

Method 1: redirect (or pipe) stdin for the loop but redirect it back for ssh

while read inst type serial; do 
  case ${inst#*-} in
  (DIF1) ssh </dev/tty -t user@host1 "sudo blah";;
  (DIF2) ssh </dev/tty -t user@host2 "sudo blech";;
  # more as needed
  esac
done <alldata 
# or cat/awk/whatever | while read ... done

Method 2: use a different unit-number (not stdin) for alldata

while read <&3 inst type serial; do
  case ${inst#*-} in
  (DIF1) ssh -t user@host1 "sudo blah";;
  (DIF2) ssh -t user@host2 "sudo blech";;
  # more
  esac
done 3<alldata 
# or while read ... done 3< <(cat/awk/whatever) with zsh/bash

Method 3 is to use a for loop (which you didn't even though your Q says you did) which reads from its arguments without any channel. For your original Q which only actually used one field this is easy:

IFS='
' # split on newline only
set -o noglob # disable globbing
for inst in $(awk '{print $1}' alldata); do
  # as for method 2
done

but your edit says you want to use at least one other field so you'd need something uglier like:

IFS='
' # split on newline only
set -o noglob # disable globbing
for line in $(awk '{print $1":"$2":"$3}' alldata); do
  IFS=:; set -- $line; inst=$1; serial=$3;
  # as before
done