Okuma satırı döngüsü ilk satırdan sonra dururken kabuk betiği


108

Aşağıdaki kabuk betiğine sahibim. Amaç, hedef dosyanın her satırında (yolu betiğin girdi parametresidir) ve her satıra karşı çalışmaktır. Şimdi, sadece hedef dosyadaki ilk satırla çalışıyor gibi görünüyor ve bu satır işlendikten sonra duruyor. Senaryomda bir sorun mu var?

#!/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"

İçinde do_work.shbirkaç sshkomut çalıştırıyorum .


1
Senaryonuz iyi, ancak do_work.sh ile ilgili bir sorun olabilir
43'te uyur

2
Evet, tüm girdileri tüketebilir veya veya sourceçıkış olarak ve basitçe çağrılabilir exec. Ancak bu kod gerçek görünmüyor, OP, yankının -esatır beslemesini düzgün bir şekilde göstermesi gerektiğini fark edecek ...
Michael Krelin - hacker

3
Herhangi bir şans eseri do_work.shçalışır mı ssh?
dogbane

1
evet, do_work.sh birkaç ssh komutu çalıştırır. bununla ilgili özel bir şey var mı?
bcbishop

1
Daha iyi, do_work.shkaynağı gösterir ve hata ayıklamak için do.shbirlikte çalışırsınız set -x.
koola

Yanıtlar:


178

Sorun, komutları do_work.shçalıştırması sshve varsayılan olarak sshgirdi dosyanız olan stdin'den okuma yapmasıdır. Sonuç olarak, yalnızca ilk satırın işlendiğini görürsünüz, çünkü sshdosyanın geri kalanını kullanır ve while döngüsünüz sona erer.

Bunu önlemek -niçin , stdin yerine sshokuma seçeneğini komutunuza geçirin /dev/null.


1
Çok faydalı, bu zsh oneliner'ı çalıştırmama yardımcı oldu: cat host | ana bilgisayar okurken; ssh $ host do_something yapmak; bitti
sıçan

3
@rat Hala işe yaramazlardancat kaçınmak istiyorsun . Özellikle bir kemirgenin buna karşı dikkatli olacağını düşünürsünüz.
üçlü

while read host ; do $host do_something ; done < /etc/hostsbundan kaçınırdı. Bu oldukça hayat kurtarıcı, teşekkürler!
rat

httpievarsayılan olarak STDIN okuyan ve bir bash veya balık döngüsü içinde çağrıldığında aynı davranıştan muzdarip olan başka bir komuttur. http --ignore-stdinStandart girişi /dev/nullyukarıdaki gibi kullanın veya ayarlayın .
Raman

13

Daha genel olarak, spesifik olmayan bir geçici çözüm, sshaksi takdirde whiledöngünün girişini tüketebilecek herhangi bir komut için standart girişi yeniden yönlendirmektir .

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

Eklenmesi </dev/null(ayrıca biraz önemlidir alıntı düzeltilmiş olsa; ayrıca bkz burada önemli bir noktadır bir kabuk değişkeni tırnak içine alın sarmak için zaman? ). read -rOnsuz elde ettiğiniz mirası biraz garip davranışa özellikle ihtiyaç duymadığınız sürece kullanmak isteyeceksiniz -r.

Bir şekilde spesifik olan başka bir geçici çözüm, sshherhangi bir sshkomutun standart girişinin bağlı olduğundan emin olmaktır , örneğin, değiştirerek

ssh otherhost some commands here

bunun yerine, komutların standart girişini uygun bir şekilde (bu özel senaryo için) bağlayan buradaki bir belgeden komutları okumak için ssh:

ssh otherhost <<'____HERE'
    some commands here
____HERE

5

ssh -n seçeneği, çıktıyı başka bir programa aktarırken HEREdoc kullanıldığında ssh çıkış durumunun kontrol edilmesini engeller. Bu yüzden / dev / null'un stdin olarak kullanılması tercih edilir.

#!/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

Bu mantıklı değil. Yeniden yönlendirmeyi <<EOFgeçersiz kılar </dev/null. <<Sonra yönlendirme doneyanlıştır.
üçlü

1

Ben çünkü bu bana da oluyordu set -eve bir grepbir döngü içinde (sıfır olmayan bir hata kodu verir ki) hiçbir çıkış ile dönüyordu.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.