Search code examples
bashscp

SCP copy from another host if file not found in one host


I know the name of the file and the host machines on which it could be. I also know that only one of the hosts has that file. So based on this reply I created the following script.

if scp "username@host1:/tmp/$1*" ~/$1;
then echo "done";
else scp "username@host2:/tmp/$1*" ~/$1;
fi

I have put the above code in a file name file_copy.sh and then invoke the file from the terminal as follows $ ./file_copy.sh filename, that is where the $1 argument comes from. I am not sure of the entire file name, but only the prefix in this case, so there is a wild card of * but that part can be ignored for this question.

In the above case, I know there are two hosts, and one of them will have my file, so I just do an if else switch, but it feels way too hacky and not elegant enough.

Question:

  1. Is there a better solution to if then else above to doing the SCP?
  2. In both the if and else branch I use SCP, which requires me to type the password twice. On both the hosts, the user name and password are the same. Is there any way, in the shell file, that I do not have to enter the password again on the terminal.
  3. The above case has two hosts, but if I have n hosts and a similar situation. That is one file, in one host, but not sure which one, but all hosts have the same user name and password credentials. How the above script can be generalized. Is there a way to make a switch case in shell script.

Thanks


Solution

    1. You could use rsync instead. rsync -r -z -c will return better error codes.

    2. You could use sshpass to automatically enter a password

    Then you could..

    if sshpass PA55WORD rsync -r -z -c "username@host1:/tmp/$1*" ~/$1;
    then echo "done";
    else sshpass PASSWORD rsync -r -z -c "username@host2:/tmp/$1*" ~/$1;
    fi
    

    I would personally recommend against typing a password in plain text. ssh private keys are useful for this exact problem. You could use sshpass -f FILE_PATH or some other clever encryption method of getting the password in, but sshpass is your friend here.

    1. For multiple hosts, all with the same username and password:
    HOSTS=( "host1" "host2" "host3" )
    
    for H in ${HOSTS[@]}
    do
      sshpass -p PASSWORD rsync -r -z -c "username@${H}:/tmp/$1*" ~/$1 && break
    done
    

    For multiple hosts, all with different usernames and passwords

    HOSTS=( "host1" "host2" "host3" )
    USERS=( "user1" "user2" "user3" )
    PASSS=( "pass1" "pass2" "pass3" )
    
    for i in ${!HOSTS[@]}
    do
      sshpass -p ${PASSS[$i]} rsync -r -z -c "${USERS[$i]}@${HOSTS[$i]}:/tmp/$1*" ~/$1 && break
    done