Etkili karşılaştırma Değişken varsa ve eşit değilse


3

shKomut dosyası sözdizimi ile ilgili bir sorunum var . Asus yönlendiricim için bir senaryo yazdım. Senaryo mükemmel çalışıyor. Ama bu çizgiye sahibim:

if [[ "$OldIP" && "$StartIP" != "$OldIP" ]]; then echo OK; fi

Gerçek olamayacak (ve yürütmek gerekir echo OK) sadece $StartIPve $OldIPaynı değildir. Çizgi çalışır, ancak daha verimli yapıldığını görmek isterim. Değişkenler geçerli IP adresleri içerir.

Bazı durumlarda, $OldIPhiçbir şey atanmayacak (başlatılmadı). Ancak, $OldIPyoksa, bu benim kabuğumda aynı olmadığı anlamına gelir!

Satır yapmak istemiyorum: eğer $OldIPyoksa -> farklı ise test -> çalıştır echo OK.

Satırın şu anlama gelmesini istiyorum: a) $OldIPyoksa -> son. artı b) $OldIPvarsa -> farklı olup olmadıklarını test edin -> çalıştırın echo OK.

Bu yüzden, "$OLDIP" &&mümkünse bir şekilde kaldırmak istiyorum. Gerçek bir sorun değil; öğrenmek meraklı :)

Sıralama (ancak çalışmıyor):

if [ [ "$OldIP" ] != "$StartIP" ]; then echo OK; fi

veya

if [ $OldIP != "$StartIP" ]; then echo OK; fi

istediğimi yapar, ancak OldIP boşaldığında şikayet eder (ama iyi çalışır)

süre

if [ "$OldIP" != "$StartIP" ]; then echo OK; fi

çalışır ancak OldIP'nin boş olduğunu gözardı eder


Kontrol edilmesi gereken iki şartınız var, ikisine de mantıksal olarak ihtiyacınız var. Ancak, birçok dil (bildiğim tüm kabuk komutları dahil) mantıksal operatörleri "kısa devre yapacaktır". "$ OLDIP" yanlış olarak değerlendirilirse, ifadenin geri kalanı, test edilen mantığı değiştirmeyeceği için değerlendirilmez.
user1794469

Bu erken optimizasyon gibi geliyor. Bunun gerçekten bir tıkanıklık olduğundan emin olmak için senaryoyu profillediniz mi?
Raphael Ahrens

Tamamen merak konusu. İfadenin şöyle olmasını isterim: if [["$ OldIP"! = "$ StartIP"]]; sonra yankı tamam; fi ama OldtIP'in var olmayan durumunu görmezden geliyor
Pila

Yanıtlar:


2

Açıkçası, eğer bir değere hiçbir zaman atanmamışsa veya varsa bir değişken yoktur unset. Değer olarak boş bir dize olan bir değişken var .

Standart parametre genişletme ${variable+value}, mevcut valueolduğunda dizenin yerine geçecektir variable(ayarlanmamış veya boş değildir). Bu, böyle bir varlığı test etmek için kullanılabilir:

if [ "${OldIP+x}" = "x" ] && [ "$OldIP" != "$StartIP" ]; then
    # code
fi

Sınamak ister etmek OldIPvar bash, kullanmak -vtesti:

 if [[ -v OldIP ]] && [[ "$OldIP" != "$StartIP" ]]; then
     # code
 fi

Bu sadece $OldIPve daha önce ayarlanmışsa (boş bir dizeye ayarlanmış olsa bile) dizi karşılaştırmasını gerçekleştirirdi . Testin değişkenin adını aldığını unutmayın .$StartIPOldIP-v


busyboxsh desteklemiyor -v. [ "${OldIP+set}" = set ]Orada kullanabilirsiniz .
Stéphane Chazelas

@ StéphaneChazelas Maalesef, etiketleri okumadığım ve bunun için olduğunu varsaydığım benim bash. Benim hatam. Önerin için teşekkürler.
Kusalananda

0

Bence senaryonun eskisi gibi verimli. Bu konuda kesinlikle çok fazla harcama yapmıyorsunuz.

Mantığı yazmanın başka bir yolu:

{ test -n "$OldIP" || test "$StartIP" != "$OldIP"; } && echo OK

"OldIP ayarlanmışsa veya OldIP ve StartIP farklıysa, o zaman yankı tamam" diyor.

Unutmayın, [bunun için test(1)okuyabileceğiniz başka bir ad man 1 test.

Düzenleme: Gilles'un belirttiği gibi, ( ... )ihtiyaç duymadıkları yerlerde alt kabuklar oluşturmamaya özen gösterin .

{ ... ; } yeni bir kabuk çalıştırmadan komutları gruplamak için kullanılabilir.

Kısa referans: http://www.gnu.org/software/bash/manual/html_node/Command-Grouping.html


1
Bir alt kabuk oluşturmak performansı düşürür. { test … || test …; } && echo OKbir deniz kabuğu yaratmadan aynı şeyi yapardı. Orijinali üzerinde kesin bir performans gelişimi olmazdı (kabuğa bağlı olarak belki bir şekilde ya da diğerinde hafif bir fark0.
Gilles

Sağol Gilles, ne kadar ironik, onu daha yavaş hale getirebilirim! İpucunuzu yansıtacak şekilde cevabımı güncelledim.
ssh2ksh

0

Bu istediğin şeyi yapar:

[ "${OldIP:-"$StartIP"}" != "$StartIP" ] && echo "OK"

Ayrıca bu (daha karmaşık):

${OldIP:+false} || { [[ $OldIP != $StartIP ]] && echo "OK"; }

0

Kullanıyorsanız bash, varsayılan bir ikame kullanabilirsiniz:

[[ "${OldIP:=oldunset}" != "${StartIP?StartUnset" ]] && echo "OK"

Sözdizimi , değişkenin ayarlanmamış veya boş olması durumunda ${var:-def}geçerli değerine $varveya belirtilen varsayılan değere (bu durumda def) göre değerlendirilir. Değişkenin değeri (eğer varsa) değişmez.

Sözdizimi ${var?message}, messageeğer $varunset veya null ise bir mesajla 1 hata koduyla çıkar .

Açıkça testuyumlu testlere ihtiyacınız varsa , şunları yapabilirsiniz:

[ ! -z "$OldIP" -a "$OldIP" != "$StartIP" ] && echo "OK"

2
! -z "STRING"aynı -n "STRING" (veya sadece "STRING")
cas,

İle Öneriniz ${OldIP:=unset}değerini başarısız StartIPolduğunu unset. Bunlar adından da anlaşılacağı gibi IP adresleri ise, bu ortaya çıkmayacak, ancak kodu kırılganlaştırıyor: ya komut dosyası bir gün ana bilgisayar adlarını destekliyorsa?
Gilles,

Kolayca sabitlenir. Bunu da yapacağım.
DopeGhoti
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.