GNU/Linux >> Belajar Linux >  >> Linux

Membaca Baris Dari File Dengan Bash:Untuk Vs. Ketika?

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.

Terkait:BashScript berfungsi dari Terminal tetapi tidak dari CronTab?

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?


Linux
  1. 10 alias Bash yang berguna untuk Linux

  2. File Setara ".bashrc" Dibaca Oleh Semua Shell?

  3. Bagaimana Cara Mengisi File Dengan Aliran Dari /dev/urandom Dengan Jumlah Baris Tertentu?

  1. Ganti Garis yang Mencocokkan Pola Dengan Garis Dari File Lain Secara Berurutan?

  2. Apakah Mungkin Di Bash, Untuk Mulai Membaca File Dari Offset Hitungan Byte Sewenang-wenang?

  3. Membaca Pola Grep Dari File?

  1. Awk Dari Baris Yang Berbeda?

  2. Contoh Bash For Loop dan While Loop

  3. Membaca dari file dalam perakitan