Enter ssh password using bash script, No such file or directory

I have many servers with the same password. I want to scp the same files in all of my servers. To do this i wrote script but doesn't work properly? Is it correct? how can I do it?

#!/usr/bin/env bash

export HISTFILE=


IP1="1.1.1.1
2.2.2.2
3.3.3.3
4.4.4.4"

IP2="5.5.5.5
6.6.6.6
6.6.6.6
7.7.7.7"

DIR1="1
2
3
4"

DIR2="5
100
104
135"

for ip1 in $IP1
do

    sshpass -fpass1.txt scp -r root@$IP1:/attach/res* /user/path/to/$DIR1/

done

for ip2 in $IP2
do

    sshpass -fpass2.txt scp -r root@$IP2:/attach/res* /user/path/to/$DIR2/

done

The result is:

107: No such file or directory
107: No such file or directory
107: No such file or directory
107: No such file or directory
135: No such file or directory
135: No such file or directory
135: No such file or directory
135: No such file or directory

I don't know how it is possible thank you in advance

Answers


It appears that you expect Bash to loop over one line at a time of your multi-line variables, but that is not at all how it works. A string is a string and a string with newlines in it is still just a string. You can loop over the tokens (words) in an unquoted string but there is no simple way to index into strings of the same length, as you are apparently trying to do (implicitly).

You could use Bash arrays instead:

IP1=( 1.1.1.1 2.2.2.2 3.3.3.3 4.4.4.4 )
DIR1=( 1 2 3 4 )
for idx in 0 1 2 3; do
     sshpass -fpass1.txt scp -r root@"${IP1[$idx]}":/attach/res* /user/path/to/"${DIR1[$idx]}"
done

or you could use a simple list of parameters and a here document:

while read ip dir; do
     sshpass -fpass1.txt scp -r root@$ip:/attach/res* /user/path/to/$dir/
done <<____HERE
    1.1.1.1  1
    2.2.2.2  2
    3.3.3.3  3
    4.4.4.4  4
____HERE

I tend to prefer the latter approach both as more readable and more portable. If you want to update the list, the server IP and the path are kept together, so you don't have to keep track of the index into each array (this is trivial for an array with four elements, but a real hassle the more you grow past half a dozen or so, and/or more than about two or three arrays). This syntax is portable all the way back to the original v7 Bourne shell, so it works where (a modern version of) Bash is not available.

(For your amusement, see how to implement the following with arrays.

while read user home shell groups loc; do
    cat <<-____HERE
        User:   $user
        Home:   $home
        Shell:  $shell
        Groups: $groups
        Loc:    $loc
____HERE
done <<HERE
    frodo    /home/shire    /bin/bash dev                   Mordor
    bilbo    /home/valinor  /bin/ksh  admin,dev             Undying Lands
    maisy    /home/maisy    /bin/zsh  dev                   Mouseville
    tallulah /home/tallulah /bin/sh   wheel,admin,dev,deity Dekadenz Kave
HERE

... especially as you add more users. Or maybe don't.)

You can factor out sshpass from this by using public keys (which as such I recommend), but I imagine you will still need to get the logic of this script working in one way or another.


Here are a few recommendations:

  • You can always echo line in your shell script to see what's going on.
  • You can also use set -xv to help you debug a shell script. Simply put set -xv before the part you want to debug, and set +xv to turn off the debug. You can also use export PS4="\$LINENO> " to print out the line number in your shell script.

Here's how your script will look with the set -xv. It's a really nice tool for debugging shell scripts. Use it:

export PS4="\$LINENO: "
set -xv
for ip1 in $IP1
do
    sshpass -fpass1.txt scp -r root@$IP1:/attach/res* /user/path/to/$DIR1/
done

for ip2 in $IP2
do
    sshpass -fpass2.txt scp -r root@$IP2:/attach/res* /user/path/to/$DIR2/
done
set +xv

I simply made the sshpass command echo statements since the program wouldn't work on my system anyway. Here's my output with echo. This is the command you're trying to execute:

sshpass -fpass1.txt scp -r root@1.1.1.1 2.2.2.2 3.3.3.3 4.4.4.4:/attach/res* /user/path/to/1 2 3 4/
sshpass -fpass1.txt scp -r root@1.1.1.1 2.2.2.2 3.3.3.3 4.4.4.4:/attach/res* /user/path/to/1 2 3 4/
sshpass -fpass1.txt scp -r root@1.1.1.1 2.2.2.2 3.3.3.3 4.4.4.4:/attach/res* /user/path/to/1 2 3 4/
sshpass -fpass1.txt scp -r root@1.1.1.1 2.2.2.2 3.3.3.3 4.4.4.4:/attach/res* /user/path/to/1 2 3 4/
sshpass -fpass2.txt scp -r root@5.5.5.5 6.6.6.6 6.6.6.6 7.7.7.7:/attach/res* /user/path/to/5 100 104 135/
sshpass -fpass2.txt scp -r root@5.5.5.5 6.6.6.6 6.6.6.6 7.7.7.7:/attach/res* /user/path/to/5 100 104 135/
sshpass -fpass2.txt scp -r root@5.5.5.5 6.6.6.6 6.6.6.6 7.7.7.7:/attach/res* /user/path/to/5 100 104 135/
sshpass -fpass2.txt scp -r root@5.5.5.5 6.6.6.6 6.6.6.6 7.7.7.7:/attach/res* /user/path/to/5 100 104 135/

First, that IP address is all wrong. You notice you seem to be looping, because the command is being executed the number of times you expect, but you're using the wrong variable for the IP address in the command. You have:

sshpass -fpass1.txt scp -r root@$IP1:/attach/res* /user/path/to/$DIR1/
                                ^^^^

and not:

sshpass -fpass1.txt scp -r root@$ip1:/attach/res* /user/path/to/$DIR1/
                                ^^^^

Note that $ip1 is your looping variable and $IP1 is the variable that contains all of your IP addresses. Don't call your variables by the same name that differ in case!. It would have been better if you gave them each different names. For example $ip_list1 instead of $IP1 and $ip instead of $ip1:

ip_list1="..."
for ip in $ip_list`
do
    sshpass -fpass1.txt scp -r root@$ip:/attach/res* /user/path/to/$DIR1/
done

Correcting for that issue, I get:

sshpass -fpass1.txt scp -r root@1.1.1.1:/attach/res* /user/path/to/1
2
3
4/
sshpass -fpass1.txt scp -r root@2.2.2.2:/attach/res* /user/path/to/1
2
3
4/
sshpass -fpass1.txt scp -r root@3.3.3.3:/attach/res* /user/path/to/1
2
3
4/
sshpass -fpass1.txt scp -r root@4.4.4.4:/attach/res* /user/path/to/1
2
3
4/
sshpass -fpass2.txt scp -r root@5.5.5.5:/attach/res* /user/path/to/5
100
104
135/
sshpass -fpass2.txt scp -r root@6.6.6.6:/attach/res* /user/path/to/5
100
104
135/
sshpass -fpass2.txt scp -r root@6.6.6.6:/attach/res* /user/path/to/5
100
104
135/
sshpass -fpass2.txt scp -r root@7.7.7.7:/attach/res* /user/path/to/5
100
104
135/

See the problem now? You're directory that you're scping to is not correct. It looks like you want to send your file to multiple directories, and assuming that somehow the scp command will loop through itself.

Here's my version of your program. I added an inner loop to go through each directory for each IP address:

#!/bin/bash

ip_list1="1.1.1.1   2.2.2.2   3.3.3.3    4.4.4.4" 
ip_list2="5.5.5.5   6.6.6.6   6.6.6.6    7.7.7.7" 
dir_list1="1        2         3          4" 
dir_list2="5        100       104        135" 
for ip in $ip_list1
do
    for dir in $dir_list1
    do
        echo "sshpass -fpass1.txt scp -r root@$ip:/attach/res* /user/path/to/$dir/"
    done
done

for ip in $ip_list2
do
    for dir in $dir_list2
    do
        echo "sshpass -fpass2.txt scp -r root@$ip:/attach/res* /user/path/to/$dir/"
    done
done

You don't need to set the IP list and directory list on multiple lines because the for will break the variable on white space. This is both a blessing and a curse. Or, better might leave you cursing if you're not careful. You have to make sure that there are no unintended white spaces.

The output is now a more reasonable:

sshpass -fpass1.txt scp -r root@1.1.1.1:/attach/res* /user/path/to/1/
sshpass -fpass1.txt scp -r root@1.1.1.1:/attach/res* /user/path/to/2/
sshpass -fpass1.txt scp -r root@1.1.1.1:/attach/res* /user/path/to/3/
sshpass -fpass1.txt scp -r root@1.1.1.1:/attach/res* /user/path/to/4/
sshpass -fpass1.txt scp -r root@2.2.2.2:/attach/res* /user/path/to/1/
sshpass -fpass1.txt scp -r root@2.2.2.2:/attach/res* /user/path/to/2/
sshpass -fpass1.txt scp -r root@2.2.2.2:/attach/res* /user/path/to/3/
sshpass -fpass1.txt scp -r root@2.2.2.2:/attach/res* /user/path/to/4/
sshpass -fpass1.txt scp -r root@3.3.3.3:/attach/res* /user/path/to/1/
sshpass -fpass1.txt scp -r root@3.3.3.3:/attach/res* /user/path/to/2/
sshpass -fpass1.txt scp -r root@3.3.3.3:/attach/res* /user/path/to/3/
sshpass -fpass1.txt scp -r root@3.3.3.3:/attach/res* /user/path/to/4/
sshpass -fpass1.txt scp -r root@4.4.4.4:/attach/res* /user/path/to/1/
sshpass -fpass1.txt scp -r root@4.4.4.4:/attach/res* /user/path/to/2/
sshpass -fpass1.txt scp -r root@4.4.4.4:/attach/res* /user/path/to/3/
sshpass -fpass1.txt scp -r root@4.4.4.4:/attach/res* /user/path/to/4/
sshpass -fpass2.txt scp -r root@5.5.5.5:/attach/res* /user/path/to/5/
sshpass -fpass2.txt scp -r root@5.5.5.5:/attach/res* /user/path/to/100/
sshpass -fpass2.txt scp -r root@5.5.5.5:/attach/res* /user/path/to/104/
sshpass -fpass2.txt scp -r root@5.5.5.5:/attach/res* /user/path/to/135/
sshpass -fpass2.txt scp -r root@6.6.6.6:/attach/res* /user/path/to/5/
sshpass -fpass2.txt scp -r root@6.6.6.6:/attach/res* /user/path/to/100/
sshpass -fpass2.txt scp -r root@6.6.6.6:/attach/res* /user/path/to/104/
sshpass -fpass2.txt scp -r root@6.6.6.6:/attach/res* /user/path/to/135/
sshpass -fpass2.txt scp -r root@6.6.6.6:/attach/res* /user/path/to/5/
sshpass -fpass2.txt scp -r root@6.6.6.6:/attach/res* /user/path/to/100/
sshpass -fpass2.txt scp -r root@6.6.6.6:/attach/res* /user/path/to/104/
sshpass -fpass2.txt scp -r root@6.6.6.6:/attach/res* /user/path/to/135/
sshpass -fpass2.txt scp -r root@7.7.7.7:/attach/res* /user/path/to/5/
sshpass -fpass2.txt scp -r root@7.7.7.7:/attach/res* /user/path/to/100/
sshpass -fpass2.txt scp -r root@7.7.7.7:/attach/res* /user/path/to/104/
sshpass -fpass2.txt scp -r root@7.7.7.7:/attach/res* /user/path/to/135/

Remove the echo and it should now work.


Create a key pair and distributed the public key to your servers. If you put a password on the private key, then you'll need ssh-agent running with the key loaded.


Need Your Help

Knockoutjs only validate chind class

knockout.js knockout-validation

I use Knockoutjs 3.0.0 and Knockoutjs-Validate, most time they work good. Now I have problem when I try to validate partial View Model.