LinuxQuestions.org
Review your favorite Linux distribution.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - Newbie
User Name
Password
Linux - Newbie This Linux forum is for members that are new to Linux.
Just starting out and have a question? If it is not in the man pages or the how-to's this is the place!

Notices


Reply
  Search this Thread
Old 02-08-2018, 07:28 AM   #1
Entropy1024
Member
 
Registered: Dec 2012
Location: UK
Distribution: Ubuntu 16 & 17
Posts: 131

Rep: Reputation: Disabled
for loop with 2 variables in list


I need to write a script to scp files from a few different remote servers as a backup.

ie if I have 3 machines at 1.1.1.1 1.1.1.4 & 1.1.1.7 and they all have the same port number I could use:

Code:
for ADDRESS in 1.1.1.1; 1.1.1.4; 1.1.1.7
do
 scp -P 22 me@$ADDRESS /blah...
done
However each machine has a different port number, say 3,7 & 10. Is there a way to have a second set of variables for the port number?

Code:
for ADDRESS in 1.1.1.1; 1.1.1.4; 1.1.1.7 PORT in 3; 7; 10
do
 scp -P $PORT me@$ADDRESS /blah...
done
Many thanks for any help
 
Old 02-08-2018, 07:53 AM   #2
michaelk
Moderator
 
Registered: Aug 2002
Posts: 25,714

Rep: Reputation: 5899Reputation: 5899Reputation: 5899Reputation: 5899Reputation: 5899Reputation: 5899Reputation: 5899Reputation: 5899Reputation: 5899Reputation: 5899Reputation: 5899
While there are several ways to do it in a loop I would use a local ssh config file i.e ~/.ssh/config.

Code:
host server1
     hostname 1.1.1.1
     user username
     port 3
host server2
    ...
host server3
    ...
Code:
for name in server1; server2; server3
do
 scp $name:/blah  blah
done

Last edited by michaelk; 02-08-2018 at 07:54 AM.
 
Old 02-08-2018, 07:54 AM   #3
keefaz
LQ Guru
 
Registered: Mar 2004
Distribution: Slackware
Posts: 6,552

Rep: Reputation: 872Reputation: 872Reputation: 872Reputation: 872Reputation: 872Reputation: 872Reputation: 872
You could use bash associative array
Code:
declare -A hosts

hosts["1.1.1.1"]=3
hosts["1.1.1.4"]=7
hosts["1.1.1.7"]=10

for ADDRESS in "${!hosts[@]}"
do
  scp -P "${hosts[$ADDRESS]}" me@$ADDRESS /blah...
done
 
Old 02-08-2018, 09:21 AM   #4
TenTenths
Senior Member
 
Registered: Aug 2011
Location: Dublin
Distribution: Centos 5 / 6 / 7
Posts: 3,475

Rep: Reputation: 1553Reputation: 1553Reputation: 1553Reputation: 1553Reputation: 1553Reputation: 1553Reputation: 1553Reputation: 1553Reputation: 1553Reputation: 1553Reputation: 1553
Could also use something like this:

Code:
#!/bin/bash

for hostport in 1.1.1.1:3 1.1.1.4:7 1.1.1.7:10 ; do

  host=$(echo ${hostport} | awk -F: {'print $1'})
  port=$(echo ${hostport} | awk -F: {'print $2'})

  echo Host ${host}
  echo Port ${port}

done
Personally I like the solution keefaz proposes though!
 
Old 02-08-2018, 10:01 AM   #5
Entropy1024
Member
 
Registered: Dec 2012
Location: UK
Distribution: Ubuntu 16 & 17
Posts: 131

Original Poster
Rep: Reputation: Disabled
Quote:
Originally Posted by michaelk View Post
While there are several ways to do it in a loop I would use a local ssh config file i.e ~/.ssh/config.

Code:
host server1
     hostname 1.1.1.1
     user username
     port 3
host server2
    ...
host server3
    ...
Code:
for name in server1; server2; server3
do
 scp $name:/blah  blah
done
Many thanks, that worked a treat.

Thanks for all the other solutions also. Very interesting.
 
Old 02-08-2018, 10:11 AM   #6
TenTenths
Senior Member
 
Registered: Aug 2011
Location: Dublin
Distribution: Centos 5 / 6 / 7
Posts: 3,475

Rep: Reputation: 1553Reputation: 1553Reputation: 1553Reputation: 1553Reputation: 1553Reputation: 1553Reputation: 1553Reputation: 1553Reputation: 1553Reputation: 1553Reputation: 1553
Quote:
Originally Posted by Entropy1024 View Post
Many thanks, that worked a treat.

Thanks for all the other solutions also. Very interesting.
My issue with michaelk's solution is that it's "hidden" from anyone else that goes back to the script and has to try and work out WHY the connections are being made on non-standard ports, or to add another server on a non-standard port. Of course you COULD put in the script notes that it uses the ssh/config file.

The other solutions are more readable and make it easier for anyone looking at the script (and yourself in a couple years time!) to work out how it's being done. They are also "transportable" to other servers without having to remember to alter your ssh config file.
 
Old 02-08-2018, 10:19 AM   #7
michaelk
Moderator
 
Registered: Aug 2002
Posts: 25,714

Rep: Reputation: 5899Reputation: 5899Reputation: 5899Reputation: 5899Reputation: 5899Reputation: 5899Reputation: 5899Reputation: 5899Reputation: 5899Reputation: 5899Reputation: 5899
True and as stated you could add comments. The other benefit of using a config file is that provides options defined per host. If you have several servers with many/different options you do not have to remember them nor have to type them on the command line. It works for ssh, scp, sftp and rsync.
 
Old 02-08-2018, 02:12 PM   #8
scasey
LQ Veteran
 
Registered: Feb 2013
Location: Tucson, AZ, USA
Distribution: CentOS 7.9.2009
Posts: 5,727

Rep: Reputation: 2211Reputation: 2211Reputation: 2211Reputation: 2211Reputation: 2211Reputation: 2211Reputation: 2211Reputation: 2211Reputation: 2211Reputation: 2211Reputation: 2211
I prefer to use the ~/.ssh/config file myself, but to TenTenths point, every time I need to make a change or configure a new server, I have to remember that's how it works.
It can also provide different options for different users, just to be more confusing.

Last edited by scasey; 02-08-2018 at 02:13 PM.
 
Old 02-09-2018, 08:35 AM   #9
MadeInGermany
Senior Member
 
Registered: Dec 2011
Location: Simplicity
Posts: 2,798

Rep: Reputation: 1201Reputation: 1201Reputation: 1201Reputation: 1201Reputation: 1201Reputation: 1201Reputation: 1201Reputation: 1201Reputation: 1201
A while read loop can break the input line into words
Code:
while read addr port <&3
do
  scp -P "$port" me@"$addr" /blah...
done 3<<EOT
1.1.1.1 3
1.1.1.4 7
1.1.1.7 10
EOT
The data is in a classic here document.
bash can take a here string, that maybe has a smaller footprint (no temp file):
Code:
#!/bin/bash
while read addr port <&3
do
  scp -P "$port" me@"$addr" /blah...
done 3<<< "\
1.1.1.1 3
1.1.1.4 7
1.1.1.7 10"
The extra file descriptor 3 makes the while loop robust against commands that read from stdin, like ssh (without -n). Certainly not needed here.
A custom input field separator can be set and/or a further field can be added, as follows:
Code:
while IFS=":" read addr port user <&3
do
  scp -P "$port" "$user@$addr" /blah...
done 3<<EOT
1.1.1.1:3:me
1.1.1.4:7:me
1.1.1.7:10:you
EOT

Last edited by MadeInGermany; 02-09-2018 at 09:30 AM. Reason: Example: custom IFS and a further input field
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
awk while loop over two variables johnpaulodonnell Linux - Newbie 2 05-14-2012 03:22 PM
[SOLVED] Passing a list of variables to a for loop pdr_dan Linux - Newbie 5 03-21-2011 12:38 PM
Loop with variables sebastiaankop Linux - Newbie 2 01-06-2011 08:35 AM
Loop with 2 variables tensigh Programming 7 11-17-2009 07:07 PM
Using for loop on 2 variables muazfarooqaslam Linux - Newbie 8 02-01-2008 08:03 AM

LinuxQuestions.org > Forums > Linux Forums > Linux - Newbie

All times are GMT -5. The time now is 03:12 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration