Skrip shell sementara loop baris baca berhenti setelah baris pertama


107

Saya memiliki skrip shell berikut. Tujuannya adalah untuk melakukan perulangan melalui setiap baris dari file target (yang jalurnya adalah parameter input ke skrip) dan bekerja pada setiap baris. Sekarang, tampaknya hanya berfungsi dengan baris pertama di file target dan berhenti setelah baris itu diproses. Apakah ada yang salah dengan skrip saya?

#!/bin/bash
# SCRIPT: do.sh
# PURPOSE: loop thru the targets 

FILENAME=$1
count=0

echo "proceed with $FILENAME"

while read LINE; do
   let count++
   echo "$count $LINE"
   sh ./do_work.sh $LINE
done < $FILENAME

echo "\ntotal $count targets"

Di do_work.sh, saya menjalankan beberapa sshperintah.


1
Skrip Anda baik-baik saja, tetapi mungkin ada yang salah dengan do_work.sh
sleepsort

2
Ya, itu bisa memakan semua masukan, atau bisa juga dipanggil sebagai sourcedan hanya keluar atau exec. Tetapi kode ini tidak terlihat asli, OP akan melihat bahwa gema memerlukan -euntuk menampilkan umpan baris dengan benar ...
Michael Krelin - peretas

3
Apakah do_work.shdijalankan sshsecara kebetulan?
dogbane

1
ya, do_work.sh menjalankan beberapa perintah ssh. sesuatu yang istimewa tentang itu?
bcbishop

1
Lebih baik Anda menunjukkan do_work.shsumbernya dan juga menjalankan do.shdengan set -xuntuk debug.
koola

Jawaban:


178

Masalahnya adalah do_work.shmenjalankan sshperintah dan secara default sshmembaca dari stdin yang merupakan file input Anda. Akibatnya, Anda hanya melihat baris pertama diproses, karena sshmenggunakan sisa file dan loop sementara Anda berakhir.

Untuk mencegah hal ini, berikan -nopsi ke sshperintah Anda untuk membuatnya dibaca /dev/nullalih-alih stdin.


1
Sangat berguna, membantu saya menjalankan zsh oneliner: cat hosts | saat membaca tuan rumah; melakukan ssh $ host do_something; selesai
tikus

3
@rat Anda masih ingin menghindari yang tidak berguna cat. Anda akan mengira hewan pengerat khususnya akan waspada terhadap hal ini.
tripleee

while read host ; do $host do_something ; done < /etc/hostsakan menghindarinya. Itu cukup menyelamatkan hidup, terima kasih!
tikus

httpieadalah perintah lain yang membaca STDIN secara default, dan akan mengalami perilaku yang sama saat dipanggil di dalam loop bash atau fish. Gunakan http --ignore-stdinatau setel input standar /dev/nullseperti di atas.
Raman

12

Secara lebih umum, solusi yang tidak spesifik sshadalah dengan mengalihkan input standar untuk perintah apa pun yang mungkin menggunakan whileinput loop.

while read -r LINE; do
   let count++
   echo "$count $LINE"
   sh ./do_work.sh "$LINE" </dev/null
done < "$FILENAME"

Penambahan </dev/nulladalah poin krusial di sini (meskipun kutipan yang dikoreksi juga agak penting; lihat juga Kapan membungkus kutipan di sekitar variabel shell? ). Anda akan ingin menggunakan read -rkecuali Anda secara khusus membutuhkan perilaku warisan yang sedikit aneh yang Anda dapatkan tanpa -r.

Jenis solusi lain yang agak spesifik sshadalah memastikan setiap sshperintah memiliki input standar yang terikat, misalnya dengan mengubah

ssh otherhost some commands here

untuk membaca perintah dari dokumen di sini, yang dengan mudah (untuk skenario khusus ini) mengikat input standar sshuntuk perintah:

ssh otherhost <<'____HERE'
    some commands here
____HERE

5

Opsi ssh -n mencegah pengecekan status keluar dari ssh saat menggunakan HEREdoc saat menyalurkan output ke program lain. Jadi penggunaan / dev / null sebagai stdin lebih disukai.

#!/bin/bash
while read ONELINE ; do
   ssh ubuntu@host_xyz </dev/null <<EOF 2>&1 | filter_pgm 
   echo "Hi, $ONELINE. You come here often?"
   process_response_pgm 
EOF
   if [ ${PIPESTATUS[0]} -ne 0 ] ; then
      echo "aborting loop"
      exit ${PIPESTATUS[0]}
   fi
done << input_list.txt

Ini tidak masuk akal. The <<EOFmenimpa </dev/nullredirection. The <<redirection setelah donesalah.
tripleee

1

Ini terjadi pada saya karena saya telah set -edan grepdalam satu loop kembali tanpa output (yang memberikan kode kesalahan bukan nol).

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.