Bash değişken kapsamı


104

Lütfen bana son echocümlenin neden boş olduğunu açıklayın. Bunun XCODEwhile döngüsünde 1 değerine yükseltilmesini bekliyorum :

#!/bin/bash
OUTPUT="name1 ip ip status" # normally output of another command with multi line output

if [ -z "$OUTPUT" ]
then
        echo "Status WARN: No messages from SMcli"
        exit $STATE_WARNING
else
        echo "$OUTPUT"|while read NAME IP1 IP2 STATUS
        do
                if [ "$STATUS" != "Optimal" ]
                then
                        echo "CRIT: $NAME - $STATUS"
                        echo $((++XCODE))
                else
                        echo "OK: $NAME - $STATUS"
                fi
        done
fi

echo $XCODE

++XCODEYöntem yerine aşağıdaki ifadeyi kullanmayı denedim

XCODE=`expr $XCODE + 1`

ve while ifadesinin dışında da yazdırılmaz. Sanırım burada değişken kapsam hakkında bir şey kaçırıyorum, ancak eski adam sayfası bunu bana göstermiyor.


XCODE'u artırılabilen bir şeye nerede başlatırsınız?
Paul Tomblin

Kodun üst kısmına while ifadesinin dışına bir "XCODE = 0" atmaya çalıştım
Matt P

Zalimlik olmadan, benim için çalışıyor. 1 2 3 4 5 içindeki i için #! / bin / bash; do echo $ ((++ XCODE)) done echo "fin:" $ XCODE Bence probleminizin değişken kapsam belirleme ile hiçbir ilgisi yok ve bu arada olanlarla ilgili her şey.
Paul Tomblin

Kabul edildi .. "okurken" döngüsü ile bir ilgisi var gibi görünüyor?
Matt P

Bununla ilgili bir Bash SSS'si var: mywiki.wooledge.org/BashFAQ/024
Fabio diyor

Yanıtlar:


117

While döngüsüne borulama yaptığınız için while döngüsünü çalıştırmak için bir alt kabuk oluşturulur.

Artık bu çocuk sürecin kendi ortam kopyası var ve herhangi bir değişkeni üstüne geri gönderemez (herhangi bir unix işleminde olduğu gibi).

Bu nedenle, döngüye girmemek için yeniden yapılandırmanız gerekecek. Alternatif olarak, örneğin bir işlevde çalıştırabilirsiniz echove alt işlemden döndürülmesini istediğiniz değer.

http://tldp.org/LDP/abs/html/subshells.html#SUBSHELL


2
bu sadece bash komut dosyasıyla karşılaştığım görünüşte rastgele sorunların çoğunu yanıtladı.
Daniel Agans

Bu mükemmel cevap beni çok üzüyor ve CI sistemimizdeki gerçekten garip bir davranışı açıklıyor.
KayCee

108

Sorun, bir boru ile bir araya getirilen işlemlerin alt kabuklarda yürütülmesidir (ve bu nedenle kendi ortamlarına sahiptir). İçinde ne olursa olsun while, borunun dışındaki hiçbir şeyi etkilemez.

Özel örneğiniz boruyu yeniden yazarak çözülebilir.

while ... do ... done <<< "$OUTPUT"

ya da belki

while ... do ... done < <(echo "$OUTPUT")

32
Bu <() sözdiziminin (benim gibi) ne olduğu konusunda kafası karışmış durumda olanlar için, buna "İşlem Değiştirme" adı verilir ve yukarıda ayrıntılı olarak açıklanan özel kullanım burada görülebilir: mywiki.wooledge.org/ProcessSubstitution
Ross Aiken

2
Süreç Değiştirme, herkesin düzenli olarak kullanması gereken bir şeydir! Süper kullanışlıdır. vimdiff <(grep WARN log.1 | sort | uniq) <(grep WARN log.2 | sort | uniq)Her gün olduğu gibi bir şey yapıyorum . Aynı anda birden çok kullanabileceğinizi ve bunları dosya gibi ele alabileceğinizi düşünün ... OLASILIKLAR!
Bruno Bronosky

8

Bu da çalışmalıdır (çünkü echo ve while aynı alt kabuktadır):

#!/bin/bash
cat /tmp/randomFile | (while read line
do
    LINE="$LINE $line"
done && echo $LINE )

3

Bir seçenek daha:

#!/bin/bash
cat /some/file | while read line
do
  var="abc"
  echo $var | xsel -i -p  # redirect stdin to the X primary selection
done
var=$(xsel -o -p)  # redirect back to stdout
echo $var

DÜZENLEME: Burada xsel bir gerekliliktir (kurun). Alternatif olarak, xclip: xclip -i -selection clipboard yerine xsel -i -p


Bir hata alıyorum: ./scraper.sh: line 111: xsel: command not found ./scraper.sh: line 114: xsel: command not found
3kstc

@ 3kstc tabii ki, xsel'i kurun. Ayrıca xclip'i de kullanabilirsiniz, ancak kullanımı biraz farklıdır. Buradaki ana nokta: 1. çıktıyı bir panoya koyarsınız (bunlardan 3 tanesi linux'ta), 2. - oradan alır ve stdout'a gönderirsiniz.
Rammix

1
 #!/bin/bash
 OUTPUT="name1 ip ip status"
+export XCODE=0;
 if [ -z "$OUTPUT" ]
----

                     echo "CRIT: $NAME - $STATUS"
-                    echo $((++XCODE))
+                    export XCODE=$(( $XCODE + 1 ))
             else

echo $XCODE

bu değişikliklerin yardımcı olup olmadığına bakın


Bunu yaparken, son yankı ifadesini yazdırmak için şimdi bir "0" alıyorum. ancak değerin sıfır değil 1 olmasını bekliyorum. Ayrıca neden ihracat kullanılıyor? Bunun onu çevreye zorladığını varsayıyorum?
Matt P

0

Diğer bir seçenek, sonuçları alt kabuktan bir dosyaya çıkarmak ve ardından bunu ana kabukta okumaktır. gibi bir şey

#!/bin/bash
EXPORTFILE=/tmp/exportfile${RANDOM}
cat /tmp/randomFile | while read line
do
    LINE="$LINE $line"
    echo $LINE > $EXPORTFILE
done
LINE=$(cat $EXPORTFILE)

0

Kendi küçük duamı yaparken bunu aştım:

ls -l | sed '/total/d ; s/  */\t/g' | cut -f 5 | 
( SUM=0; while read SIZE; do SUM=$(($SUM+$SIZE)); done; echo "$(($SUM/1024/1024/1024))GB" )

Mesele şu ki, SUM değişkenimi ve while'ı içeren () ile bir alt kabuk yapıyorum, ancak süre yerine bütün () 'e aktarıyorum, bu da gotcha'yı engelliyor.

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.