Saya mencoba membaca file teks dan melakukan sesuatu dengan setiap baris, menggunakan skrip bash.
Jadi, saya punya daftar yang terlihat seperti ini:
server1
server2
server3
server4
Saya pikir saya bisa mengulang ini menggunakan loop sementara, seperti:
while read server; do
ssh $server "uname -a"
done < /home/kenny/list_of_servers.txt
Perulangan while berhenti setelah 1 kali dijalankan, sehingga hanya menjalankan uname -a
di server1
Namun, dengan for loop menggunakan cat berfungsi dengan baik:
for server in $(cat /home/kenny/list_of_servers.txt) ; do
ssh $server "uname -a"
done
Yang lebih membingungkan saya adalah ini juga berfungsi:
while read server; do
echo $server
done < /home/kenny/list_of_servers.txt
Mengapa contoh pertama saya berhenti setelah iterasi pertama?
Jawaban yang Diterima:
for
lingkaran baik-baik saja di sini. Tetapi perhatikan bahwa ini karena file tersebut berisi nama mesin, yang tidak mengandung karakter spasi putih atau karakter globbing. for x in $(cat file); do …
tidak berfungsi untuk mengulangi baris file
secara umum, karena shell pertama membagi output dari perintah cat file
di mana saja ada spasi, dan kemudian memperlakukan setiap kata sebagai pola glob jadi \[?*
lebih diperluas. Anda dapat membuat for x in $(cat file)
aman jika Anda mengerjakannya:
set -f
IFS='
'
for x in $(cat file); do …
Bacaan terkait:Perulangan file dengan spasi di namanya?; Bagaimana saya bisa membaca baris demi baris dari variabel di bash?; Mengapa while IFS= read
sering digunakan, sebagai ganti IFS=; while read..
? Perhatikan bahwa saat menggunakan while read
, sintaks yang aman untuk membaca baris adalah while IFS= read -r line; do …
.
Sekarang mari kita beralih ke apa yang salah dengan while read
percobaan. Pengalihan dari file daftar server berlaku untuk seluruh loop. Jadi ketika ssh
berjalan, input standarnya berasal dari file itu. Klien ssh tidak dapat mengetahui kapan aplikasi jarak jauh mungkin ingin membaca dari input standarnya. Jadi segera setelah klien ssh memperhatikan beberapa input, ia mengirimkan input itu ke sisi jarak jauh. Server ssh di sana kemudian siap untuk memasukkan input itu ke perintah jarak jauh, jika ia menginginkannya. Dalam kasus Anda, perintah jarak jauh tidak pernah membaca input apa pun, sehingga data akhirnya dibuang, tetapi sisi klien tidak tahu apa-apa tentang itu. Upaya Anda dengan echo
bekerja karena echo
tidak pernah membaca input apa pun, ia membiarkan input standarnya saja.
Ada beberapa cara yang bisa Anda lakukan untuk menghindari hal ini. Anda dapat memberitahu ssh untuk tidak membaca dari input standar, dengan -n
pilihan.
while read server; do
ssh -n $server "uname -a"
done < /home/kenny/list_of_servers.txt
-n
opsi sebenarnya memberi tahu ssh
untuk mengarahkan ulang inputnya dari /dev/null
. Anda dapat melakukannya di tingkat shell, dan ini akan berfungsi untuk perintah apa pun.
while read server; do
ssh $server "uname -a" </dev/null
done < /home/kenny/list_of_servers.txt
Metode menggoda untuk menghindari input ssh yang berasal dari file adalah dengan menempatkan pengalihan pada read
perintah:while read server </home/kenny/list_of_servers.txt; do …
. Ini tidak akan berhasil, karena menyebabkan file dibuka kembali setiap kali read
perintah dieksekusi (sehingga akan membaca baris pertama file berulang-ulang). Pengalihan harus dilakukan di seluruh loop while sehingga file dibuka satu kali selama loop berlangsung.
Solusi umum adalah memberikan input ke loop pada deskriptor file selain input standar. Shell memiliki konstruksi untuk mengangkut input dan output dari satu nomor deskriptor ke nomor lainnya. Di sini, kami membuka file pada deskriptor file 3, dan mengarahkan ulang read
input standar perintah dari deskriptor file 3. Klien ssh mengabaikan deskriptor non-standar terbuka, jadi semuanya baik-baik saja.
while read server <&3; do
ssh $server "uname -a"
done 3</home/kenny/list_of_servers.txt
Di bash, read
perintah memiliki opsi khusus untuk membaca dari deskriptor file yang berbeda, sehingga Anda dapat menulis read -u3 server
.
Bacaan terkait:File deskriptor &skrip shell; Kapan Anda akan menggunakan deskriptor file tambahan?