Bash: prompt jauh interaktif


16

Saya memiliki skrip yang terhubung ke server jauh dan memeriksa apakah beberapa paket diinstal:

ssh root@server 'bash -s' < myscript.sh

myscript.sh:

OUT=`rpm -qa | grep ntpdate`
if [ "$OUT" != "" ] ; then
    echo "ntpdate already installed"
else
    yum install $1
fi

Contoh ini dapat disederhanakan. Inilah myscript2.shyang memiliki masalah yang sama:

read -p "Package is not installed. Do you want to install it (y/n)?" choise

Masalah saya adalah bahwa bash tidak dapat membaca jawaban saya secara interaktif.

Apakah ada cara untuk mengeksekusi skrip lokal dari jarak jauh tanpa kehilangan kemampuan untuk meminta pengguna?


Bisakah Anda menguraikan? Tidak jelas apa yang Anda minta? Beberapa kode Anda akan sangat membantu.
slm

1
Hanya FYI, alasan ini tidak berhasil adalah karena Anda melewati skrip Anda di atas STDIN. Jadi ketika bash pergi untuk membaca dari STDIN, ia mendapatkan skrip Anda (atau tidak sama sekali karena sudah membaca seluruh skrip dan tidak ada yang tersisa).
Patrick

1
Sumber daya yang berguna terkait dengan ini: backreference.org/2011/08/10/…
slm

Jawaban:


22

Coba sesuatu seperti ini:

$ ssh -t yourserver "$(<your_script)"

The -tpasukan alokasi tty, $(<your_script)membaca seluruh file dan dalam kasus ini melewati konten sebagai salah satu argumen untukssh , yang akan dieksekusi oleh shell pengguna remote.

Jika skrip membutuhkan parameter, berikan setelah skrip:

$ ssh -t yourserver "$(<your_script)" arg1 arg2 ...

Bekerja untuk saya, tidak yakin apakah itu universal.


3
Itulah tepatnya yang saya cari, terima kasih!
Anthony Ananich

Solusi yang bagus, tetapi apakah ada cara untuk menyampaikan argumen your script, sambil tetap mempertahankan keunggulan sintaks yang Anda gunakan dalam jawaban Anda? Hanya menggunakan ssh -t yourserver "$(<your_script --some_arg)"hasil dalam bash: --some_arg: command not found.
sampablokuper

1
@sampablokuper: tryssh ... $(<script) script_arg1 script_arg2 ...
Mat

@Mat, terima kasih, WFM :) Mungkin menambahkannya ke badan jawaban Anda?
sampablokuper

3

Masalah Anda adalah sshmemulai shell yang non-interaktif di mesin remote. Solusi mudah yang jelas adalah menyalin skrip ke server jauh dan menjalankannya dari sana:

scp myscript.sh root@server:/tmp && ssh root@server /tmp/myscript.sh

Jika penyalinan bukanlah suatu pilihan untuk alasan apa pun, saya akan memodifikasi skrip untuk menghubungkan terlebih dahulu dan memeriksa apakah $1sudah diinstal, kemudian menyambung kembali dan menginstal seperlunya:

OUT=$(ssh root@server rpm -qa | grep "$1");
if [ "$OUT" != "" ] ; then
    echo "$1 already installed"
else
   read -p "Package $1 is not installed. Do you want to install it (y/n)?" choice
   if [ "$choice" -eq "y" ]; then
       ssh root@server yum install "$1"
   fi
fi

Itu yang saya takutkan. Koneksi ke ssh adalah operasi terpanjang dan saya berusaha menghindarinya.
Anthony Ananich

@AnthonyAnanich Anda dapat menghemat waktu pembuatan koneksi dengan mengatur koneksi master .
Gilles 'SO- berhenti bersikap jahat'

@Gilles saya berpikir untuk menyarankan itu, tetapi saya pikir itu tidak akan berhasil dengan saran saya. Jika koneksi ssh ke-1 bertindak sebagai master, maka akan ditutup setelah $OUT=$(ssh root@server rpm -qa | grep "$1");keluar dan kemudian koneksi ke-2 akan mengambil waktu sebanyak yang pertama. Apakah aku salah?
terdon

1
@terdon Jalankan sesuatu seperti ssh -M foo.example.com sleep 99999999atau ssh -M foo.example.com read <somefifosebagai master dan bunuh secara eksplisit (dengan killatau echo done >somefifo) ketika Anda selesai.
Gilles 'SANGAT berhenti menjadi jahat'

0

Ini penjelasan yang bagus .

Jadi saya mengadaptasi skrip untuk

hostname
echo -n "Make your choice :"
read choice
echo "You typed " ${choice}
echo done

dan ini tidak berhasil.

jadi saya memindahkan script ke remote untuk menghindari redirection lokal di ssh. (Perintah saya ada di file bernama f )

cat f | ssh user@remotehost.com 'cat >remf'
ssh user@remotehost bash remf

Ini berhasil. Inilah hasilnya:

christian@clafujiu:~/tmp$ ssh localhost bash tmp/f
christian@localhost's password: 
Linux clafujiu 2.6.32-52-generic #114-Ubuntu SMP Wed Sep 11 19:00:15 UTC 2013 i686 GNU/Linux
Sun Nov 10 14:58:56 GMT 2013
Make your choice :abc
You typed  abc
done

Seperti @terdon menyebutkan bahwa kehebatan aslinya adalah untuk menjalankan skrip lokal dari jarak jauh, salinan jarak jauh dapat diotomatisasi, ini hanya satu contoh semua pada satu baris.

REMID=`cat f |ssh user@remotehost 'cat > remf_$$; echo $$'` ;ssh root@redtoadservices.com "bash remf_${REMID} ; rm -v remf_${REMID}"

2
Bagaimana cara kerjanya? Apakah Anda menjalankan skrip ini dengan bash -s < script.shseperti OP lakukan? Bisakah Anda memasukkan penjelasan dalam jawaban Anda alih-alih menghubungkannya?
terdon

Ups, maaf saya lupa menambahkan sesuatu yang penting. Saya juga menyalin skrip ke remote untuk menghindari pengalihan lokal. Saya akan menambahkan ini ke jawaban saya untuk membuatnya jelas.
X Tian

1
Jika Anda menyalin skrip ke remote, masalahnya hilang. Masalah OP adalah bahwa ia mencoba memberikan input interaktif ke skrip lokal yang dijalankan dari jarak jauh. Tentu saja itu akan berjalan ketika Anda menyalinnya. OP ingin menjalankan skrip ini saat menghubungkan ke server jarak jauh, mungkin ke banyak server jarak jauh. Saya ragu menyalin itu praktis kecuali Anda mengotomatiskannya.
terdon

0

Saya telah mencari solusi untuk masalah ini beberapa kali di masa lalu, namun tidak pernah menemukan yang sepenuhnya memuaskan. Menyalurkan ke ssh kehilangan interaktivitas Anda. Dua koneksi (scp / ssh) lebih lambat, dan file sementara Anda mungkin dibiarkan tergeletak. Dan seluruh skrip pada baris perintah sering berakhir di neraka.

Baru-baru ini saya menemukan bahwa ukuran buffer baris perintah biasanya cukup besar ('getconf ARG_MAX> 2MB di mana saya melihat). Dan ini membuat saya berpikir tentang bagaimana saya bisa menggunakan ini dan mengurangi masalah pelarian.

Hasilnya adalah:

ssh -t <host> /bin/bash "<(echo "$(cat my_script | base64 | tr -d '\n')" | base64 --decode)" <arg1> ...

atau menggunakan dokumen dan kucing di sini:

ssh -t <host> /bin/bash $'<(cat<<_ | base64 --decode\n'$(cat my_script | base64)$'\n_\n)' <arg1> ...

Saya telah memperluas gagasan ini untuk menghasilkan skrip contoh BASH yang berfungsi penuh sshxyang dapat menjalankan skrip arbitrer (tidak hanya BASH), di mana argumen dapat berupa file input lokal juga, di atas ssh. Lihat di sini .


Menarik, tetapi bagaimana dan / atau kapan ini lebih baik daripada jawaban Mat ?
Scott

1
Jawaban Mat adalah pass pertama yang baik (yang sering saya gunakan), namun Mat tidak dapat menangani skrip konten sewenang-wenang, seperti "karakter yang harus diloloskan. Dan juga dibatasi untuk skrip BASH. Solusi saya adalah kasus umum untuk konten skrip apa pun dari bahasa scripting yang diinstal. Selanjutnya, di sshx saya lebih lanjut menunjukkan file argumen serialisasi, yang cukup bagus.
SourceSimian

(1) Dapatkah Anda memposting MCVE naskah yang jawaban Matnya gagal (dan milik Anda berfungsi)? (2) Lihat Apa yang salah dengan “echo $ (stuff)” atau “echo` stuff` ”? echo "$(cat my_script | base64)" | base64 --decodePenampilan  Anda setara (-ish) untuk cat my_script | base64 | base64 --decode, yang terlihat sangat mirip no-op.
Scott

Hai @Scott. (1): Pertimbangkan script: echo "ARG1=$1, USER=$USER, END". a) $ ssh host "$(<my_bash)" foo-> ARG1=, USER=user, END foo. b) $ ssh host bash "<(echo $(cat my_bash|base64) | base64 --decode)" foo-> ARG1=foo, USER=user, END. Di sini (a) berjalan secara efektif: bash -c $'#!/bin/bash\necho "ARG1=$1, USER=$USER, END" foo'atau sesuatu yang serupa. Perhatikan arg tidak bekerja. Mana (b) adalah berjalan: bash <(echo IyEvY...5EIgo= | base64 --decode) foo. (2) Saya menggunakan base64 sebagai encoding transport.
SourceSimian
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.