Saya punya file servers.txt
, dengan daftar server:
server1.mydomain.com
server2.mydomain.com
server3.mydomain.com
ketika saya membaca file baris demi baris dengan while
dan menggema setiap baris, semua berfungsi seperti yang diharapkan. Semua garis dicetak.
$ while read HOST ; do echo $HOST ; done < servers.txt
server1.mydomain.com
server2.mydomain.com
server3.mydomain.com
Namun, ketika saya ingin ssh ke semua server dan menjalankan perintah, tiba-tiba while
loop saya berhenti berfungsi:
$ while read HOST ; do ssh $HOST "uname -a" ; done < servers.txt
Linux server1 2.6.30.4-1 #1 SMP Wed Aug 12 19:55:12 EDT 2009 i686 GNU/Linux
Ini hanya terhubung ke server pertama dalam daftar, bukan ke semuanya. Saya tidak mengerti apa yang terjadi di sini. Bisakah seseorang tolong jelaskan?
Ini bahkan lebih aneh, karena menggunakan for
loop berfungsi dengan baik:
$ for HOST in $(cat servers.txt ) ; do ssh $HOST "uname -a" ; done
Linux server1 2.6.30.4-1 #1 SMP Wed Aug 12 19:55:12 EDT 2009 i686 GNU/Linux
Linux server2 2.6.30.4-1 #1 SMP Wed Aug 12 19:55:12 EDT 2009 i686 GNU/Linux
Linux server3 2.6.30.4-1 #1 SMP Wed Aug 12 19:55:12 EDT 2009 i686 GNU/Linux
Itu harus sesuatu yang spesifik ssh
, karena perintah lain berfungsi dengan baik, seperti ping
:
$ while read HOST ; do ping -c 1 $HOST ; done < servers.txt
ssh
scripting
io-redirection
Martin Vegter
sumber
sumber
ansible
Jawaban:
ssh
sedang membaca sisa input standar Anda.read
dibaca dari stdin. The<
pengalihan stdin dari file.Sayangnya, perintah yang Anda coba jalankan juga membaca stdin, sehingga akhirnya memakan sisa file Anda. Anda dapat melihatnya dengan jelas dengan:
Perhatikan bagaimana
cat
memakan (dan menggema) dua baris yang tersisa. (Sudah membaca melakukannya seperti yang diharapkan, setiap baris akan memiliki "mulai" dan "berakhir" di sekitar host.)Kenapa
for
berhasil?Anda
for
garis tidak redirect ke stdin. (Bahkan, ia membaca seluruh isiservers.txt
file ke dalam memori sebelum iterasi pertama). Jadissh
terus membaca stdin-nya dari terminal (atau mungkin tidak sama sekali, tergantung pada bagaimana script Anda dipanggil).Larutan
Setidaknya dalam bash, Anda dapat
read
menggunakan deskriptor file yang berbeda.seharusnya bekerja.
10
hanyalah nomor file sewenang-wenang yang saya pilih. 0, 1, dan 2 telah mendefinisikan makna, dan biasanya membuka file akan dimulai dari angka pertama yang tersedia (sehingga 3 akan digunakan berikutnya). Dengan demikian 10 cukup tinggi untuk menghindar, tetapi cukup rendah untuk berada di bawah batas dalam beberapa cangkang. Ditambah dengan angka bulat yang bagus ...Solusi Alternatif 1: -n
Seperti yang ditunjukkan McNisse dalam jawabannya , klien OpenSSH memiliki
-n
opsi yang akan mencegahnya membaca stdin. Ini bekerja dengan baik dalam kasus tertentussh
, tetapi tentu saja perintah lain mungkin kekurangan ini — solusi lain bekerja terlepas dari perintah mana yang memakan stdin Anda.Solusi Alternatif 2: pengalihan kedua
Anda ternyata dapat (seperti pada, saya mencobanya, setidaknya berfungsi dalam versi Bash saya ...) melakukan redirect kedua, yang terlihat seperti ini:
Anda dapat menggunakan ini dengan perintah apa pun, tetapi akan sulit jika Anda benar-benar ingin input terminal pergi ke perintah.
sumber
10
berasal?exec 3<&0; while read HOST; do ssh $HOST "uname -a" <&3; done <servers.txt; exec 3<&-
Ini membuat file deskriptor 3 menjadi cadangan stdin asli, kemudian menggunakannya untuk stdin ssh, lalu menutup cadangan FD setelah selesai. Ini berfungsi pada semua shell yang kompatibel dengan POSIX.-u
opsi tidak didukung oleh POSIX, dan dengan demikian tidak boleh digunakan untuk#!/bin/sh
script; gunakanread HOST <&10
saja. Selain itu, POSIX hanya membutuhkan shell untuk mendukung deskriptor file 0 hingga 9, jadi10<servers.txt
tidak dapat digunakan jika skrip harus benar-benar sesuai.Seperti yang dijelaskan derobert,
ssh
bacaan Andastdin
.Untuk mengubah perilaku ini, Anda dapat menambahkan -n no ssh untuk mencegahnya membaca stdin.
sumber
Anda mungkin sebenarnya lebih baik menggunakan pssh dari proyek paralel-ssh .
-i
berarti interaktif. pssh juga dilengkapi dengan scp paralel dan rsync paralel. Apa yang baik adalah itu berjalan secara tidak sinkron dan akan menjalankan sebanyak utas yang Anda minta. Default (non -i / interaktif) adalah untuk output ke direktori terpisah untuk stdout / stderr, yang dilakukan oleh $ outputdir / $ hostname.sumber
Jika Anda sering melakukan tugas semacam ini, Anda harus mencoba Fabric
Instal Fabric mengikuti instruksi , sebagian besar kasus yang Anda butuhkan
sudo apt-get install fabric
Buat file
fabfile.py
dengan nama kode berikut:Kemudian jalankan
fab mytask
akan memberi Anda hasil yang Anda inginkan.sumber
Lebih mudah menggunakan perintah seperti ini:
Saya biasanya suka ini:
The
echo
adalah untuk melihat mana server terjebak, atau tidak dapat menyambung ke.sumber
Karena perintah ssh mengambil semua aliran dari input standar, diumpankan oleh pernyataan while,
Anda dapat menggunakan pipa untuk mengalihkan stdin ssh ke sumber lain:
contoh:
input stdin dari semua perintah ssh dalam loop sementara harus dialihkan ke sumber lain.
sumber