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
Here are a few recommendations:
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.
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.
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.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.