spawn - nie znaleziono polecenia!

15

Używam Mac OS X 10.9.4, poniżej znajduje się mój skrypt do kopiowania plików z lokalnego komputera na inny host

#!/bin/bash
#!/usr/bin/expect

echo "I will fail if you give junk values!!"
echo " "
echo "Enter file name: "
read filePath
echo " "
echo "Where you want to copy?"
echo "Enter"
echo "1. if Host1"
echo "2. if Host2"
echo "3. if Host3"
read choice
echo " "
if [ $choice -eq "1" ]
then
  spawn scp filePath uname@host1:/usr/tmp   
  expect "password"   
  send "MyPassword\r"
  interact
elif [ $choice -eq "2" ]
then
  spawn scp filePath uname@host2:/usr/tmp   
  expect "password"   
  send "MyPassword\r"
  interact
elif [ $choice -eq "3" ]
then
  spawn scp filePath uname@host3:/usr/tmp   
  expect "password"   
  send "MyPassword\r"
  interact
else
  echo "Wrong input"
fi

po uruchomieniu tego skryptu otrzymuję następujące informacje

./rcopy.sh: line 21: spawn: command not found
couldn't read file "password": no such file or directory
./rcopy.sh: line 23: send: command not found
./rcopy.sh: line 24: interact: command not found
dev2d
źródło
W moim przypadku potrzebowałem znaczników EOD wokół oczekiwanego kodu. stackoverflow.com/questions/26125036/…
AnneTheAgile

Odpowiedzi:

20

Twój skrypt próbuje połączyć dwóch tłumaczy. Masz zarówno #!/bin/bashi #!/usr/bin/expect. To nie zadziała. Możesz użyć tylko jednego z dwóch. Od bashpierwszego uruchomienia skrypt jest uruchamiany jako skrypt bash.

Jednak w twoim skrypcie masz expect takie polecenia, jak spawni send. Ponieważ skrypt jest czytany przez, basha nie przez expect, kończy się to niepowodzeniem. Można to obejść, pisząc różne expectskrypty i wywołując je ze bashskryptu lub tłumacząc całość expect.

Najlepszym sposobem jednak, który pozwala uniknąć okropnej praktyki posiadania haseł w postaci zwykłego tekstu w prostym pliku tekstowym, jest skonfigurowanie bezhasłowego ssh. W ten sposób scphasło nie będzie potrzebne i nie będziesz potrzebować expect:

  1. Najpierw utwórz publiczny klucz ssh na swoim komputerze:

    ssh-keygen -t rsa

    Zostaniesz poproszony o hasło, które zostaniesz poproszony o podanie pierwszego polecenia ssh po każdym logowaniu. Oznacza to, że w przypadku wielu poleceń ssh lub scp wystarczy wprowadzić je tylko raz. Pozostaw hasło puste, aby uzyskać dostęp całkowicie bez hasła.

  2. Po wygenerowaniu klucza publicznego skopiuj go na każdy komputer w sieci:

    while read ip; do 
     ssh-copy-id -i ~/.ssh/id_rsa.pub user1@$ip 
    done < IPlistfile.txt

    The IPlistfile.txtPowinien być plik zawierający nazwę serwera lub adres IP na każdej linii. Na przykład:

    host1
    host2
    host3

    Ponieważ robisz to po raz pierwszy, będziesz musiał ręcznie wprowadzić hasło dla każdego adresu IP, ale gdy to zrobisz, będziesz mógł skopiować pliki na dowolny z tych komputerów za pomocą prostego:

    scp file user@host1:/path/to/file
  3. Usuń oczekiwanie ze skryptu. Teraz, gdy masz dostęp bez hasła, możesz używać skryptu jako:

    #!/bin/bash
    echo "I will fail if you give junk values!!"
    echo " "
    echo "Enter file name: "
    read filePath
    echo " "
    echo "Where you want to copy?"
    echo "Enter"
    echo "1. if Host1"
    echo "2. if Host2"
    echo "3. if Host3"
    read choice
    echo " "
    if [ $choice -eq "1" ]
    then
      scp filePath uname@host1:/usr/tmp   
    elif [ $choice -eq "2" ]
    then
      scp filePath uname@host2:/usr/tmp   
    elif [ $choice -eq "3" ]
    then
      scp filePath uname@host3:/usr/tmp   
    else
      echo "Wrong input"
    fi
terdon
źródło
1
Jeśli uruchomisz agenta ssh, musisz wprowadzić hasło tylko raz. W przeciwnym razie musisz go wprowadzić za każdym razem.
glenn jackman
5

Twój kod może być o wiele bardziej zwięzły:

#!/bin/bash

read -p "Enter file name: " filePath
if ! [[ -r $filePath ]]; then
    echo "cannot read $filePath"
    exit 1
fi

PS3="Where you want to copy? "
select host in host1 host2 host3; do
    if [[ -n $host ]]; then
        expect <<END
            spawn scp "$filePath" uname@$host:/usr/tmp   
            expect "password"   
            send "MyPassword\r"
            expect eof
END
        break
    fi
done

Jeśli skonfigurujesz klucze ssh zgodnie z sugestią, jeszcze lepiej:

    if [[ -n $host ]]; then
        scp "$filePath" uname@$host:/usr/tmp   
        break
    fi
Glenn Jackman
źródło