3

The idea is to make this script run without needing to type any passwords of the hosts (written down in the Hosts.txt file). Right now, when I'm running this, I get a Permission denied, please try again. as an answer.

#!/bin/bash

[[ -z "${1}" ]] && OUT_FILE="WhereTheAnswearIsGoing.txt" || OUT_FILE="$1"
[[ -z "${2}" ]] && IN_FILE="Hosts.txt" || IN_FILE="$2"

while IFS= read -r host; do
        indication="$(sshpass -pfootbar ssh -p 2222 -o StrictHostKeyChecking=no -n "$host" 'who -b' | awk '{print $(NF-1)" "$NF}')"
        printf '%-14s %s\n' "$indication" "$host" >> "$OUT_FILE"
done < "$IN_FILE"

Sorry if this question is unclear but I don't know much about things like these.

3
  • 7
    What exactly is the error output you're receiving? Why is there a dot in your shebang line? Why does your script end with ~? What's the (or a sample) input and what output do you expect? Please edit and clarify.
    – dessert
    Commented Dec 14, 2017 at 9:56
  • 5
    if you are getting "permission denied", your script probably lacks execute permission (run chmod u+x name_of_script). But indeed it is unclear what the script is trying to do, and hopefully there is a better way of doing it without writing passwords in plain text in any file.
    – Zanna
    Commented Dec 14, 2017 at 10:02
  • 1
    "but I don't know much about things like these" - If you wrote or changed the script then you better should. Else bad things may happen, as this is security sensitive code.
    – Murphy
    Commented Dec 14, 2017 at 10:32

1 Answer 1

10

It looks the message Permission denied, please try again. is generated by the SSH client. The password should be quoted to escape the special meaning of characters as $, !, etc. (ref):

sshpass -p 'footbar' ...

Or you can use a file where the password to be stored (source):

sshpass -f "/path/to/passwordfile" ...

enter image description here


However, I remember, this is a script from my previous answer where I mentioned that: "Note here is assumed there is ~/.ssh/config file and additional parameters as -p 2222 are not needed (reference)." What I meant was:

The better solution is to (1) setup Key based SSH authentication, (2) create ~/.ssh/config file and (3) modify the script to work with this setup.

1. Setup Key based SSH authentication (source).

  • Generating RSA Keys and don't enter passphrase:

      mkdir ~/.ssh
      chmod 700 ~/.ssh
      ssh-keygen -t rsa -b 4096
      chmod 600 ~/.ssh/id_rsa
    
  • Transfer Client Key to each Host (please note the quote marks):

      ssh-copy-id "<username>@<host> -p <port_nr>"
    
  • Now you should be able to connect to the server(s) without password:

      ssh <username>@<host> -p <port_nr>
    
  • Once this works, you could disable the password authentication (that is less secure method) by editing the file /etc/ssh/sshd_config of each host machine in this way:

      #PasswordAuthentication yes
      PasswordAuthentication no
    

2. Create ~/.ssh/config file. (Read also: How do I add multiple machines with the same configuration to ~/.ssh/config?)

  • The content of the file ~/.ssh/config could look as this (host-i is object of your choice):

      Host host-1
          HostName <domain-or-IP-address>
          IdentityFile ~/.ssh/id_rsa
          User <username>
          Port 2222
          # other parameters...
    
      Host host-2
          HostName <domain-or-IP-address>
          IdentityFile ~/.ssh/id_rsa
          User <username>
          Port 2222
          # other parameters...
    
      Host host-3...
    
  • Change the file permissions:

      chmod 600 ~/.ssh/config
    
  • Now you should be able to connect to each of these hosts by a command as:

      ssh host-1
    

3.A. You can keep using the above scrip with a little modification:

#!/bin/bash

[[ -z $1 ]] && OUT_FILE="WhereTheAnswearIsGoing.txt" || OUT_FILE="$1"
[[ -z $2 ]] && IN_FILE="Hosts.txt" || IN_FILE="$2"

while IFS= read -r host; do
        indication="$(ssh -n "$host" 'who -b' | awk '{print $(NF-1)" "$NF}')"
        printf '%-14s %s\n' "$indication" "$host" >> "$OUT_FILE"
done < "$IN_FILE"

In this case the Hosts.txt file should be:

host-1
host-2
host-3

3.B. Or you can modify the script in more general way:

#!/bin/bash

# Collect the user's input, and if it`s empty set the default values
[[ -z $1 ]] && OUT_FILE="WhereTheAnswearIsGoing.txt" || OUT_FILE="$1"
# Provide the list of the hosts as an array
HOSTS=("host-1" "host-2" "host-3")

for host in "${HOSTS[@]}"; do
    indication="$(ssh -n "$host" 'who -b' | awk '{print $(NF-1)" "$NF}')"
    printf '%-14s %s\n' "$host" "$indication" >> "$OUT_FILE"
done
3
  • Interestingly for me, a password like "blahblah$dd" did not work, but when I changed the quotes to single quotes, it did.
    – ViaTech
    Commented Aug 19, 2022 at 14:28
  • 1
    Hi, @ViaTech, by default the most shells threat sequences like $dd as variables, and expanding them before run the command or do an assignment. Because there is not defined a variable named $dd - it doesn't have a value - when the shell expands it your actual password become blahblah. The purpose of the single quotes is just that - to prevent variable like strings from expansion. Another way to suppers the meaning of any (single) special character (in this case $) is to escape it by a backslash: "blahblah\$dd".
    – pa4080
    Commented Aug 19, 2022 at 18:06
  • thanks for the extra info on variable definitions in shells! Makes much more sense, I hadn't thought $ would still need escaping since it seemed having it in a str would cover it.
    – ViaTech
    Commented Aug 19, 2022 at 19:38

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .