Desteklenmeyen 'shopt' seçeneklerinin .bashrc dosyamda hatalara neden olmasını nasıl önleyebilirim?


9

Farklı HPC düğümlerinde, VM'lerde veya kişisel iş istasyonumda farklı Bash sürümleri çalıştırdığım nispeten heterojen bir ortamda çalışıyorum. Giriş betiklerimi Git deposuna koyduğum için .bashrc, "bu ana bilgisayar, o zaman ..." türünde bir karışıklık olmadan, tahtada aynı (ish) kullanmak istiyorum .

Ben gibi Bash ≤ genişletir 4.1 varsayılan davranış cd $SOMEPATHiçine cd /the/actual/pathbasıldığında Tabanahtarı. Bash 4.2 ve üzeri, sen gerekir shopt -s direxpandbu davranışı yeniden etkinleştirmek ve bu kullanılabilir hale vermedi 4.2.29 kadar . Yine de bu sadece bir örnek; başka bir, muhtemelen ilişkili bir shoptseçenek, complete_fullquote( tam olarak ne yaptığını bilmiyorum olsa da) v4.2'deki varsayılan davranışı da değiştirmiş olabilir.

Ancak, direxpandBash'in önceki sürümleri tarafından tanınmaz ve eğer shopt -s direxpandbenim .bashrciçin denersem, daha eski bir Bash ile bir düğüme her giriş yaptığımda bu bir hata mesajının konsola yazdırılmasına neden olur:

-bash: shopt: direxpand: invalid shell option name

Ne yapmak istiyorum shop -s direxpandBash> 4.1 bu seçeneği sağlam bir şekilde Bash eski sürümleri chafs olmadan etkinleştirmek için bir koşul sarmak ( yani , sadece hata çıkışını yeniden yönlendirmek değil /dev/null).


Cevabım nasıl yardımcı olmadı?
Luciano Andress Martini

@LucianoAndressMartini Yaptı ve kendi başıma yaptığım çözüm buydu .bashrc. Hala $BASH_VERSINFOkendi kabuğum için koşu kabuğunun büyük / küçük sürümünü sorgulamak için nasıl kullanılacağına dair bir kayıt istedim , bu yüzden kendi cevabımı göndermeyi bitirdim. :)
thedudeabides

Cevabımda bak ben program betiği kabuk betiği ile karşılaştırma hakkında bir şey var.
Luciano Andress Martini

Yanıtlar:


14

Çıktısında direxpandmevcut olup olmadığını kontrol edin shoptve varsa etkinleştirin:

shopt | grep -q '^direxpand\b' && shopt -s direxpand

4
O daha iyi yapmak grep -q '^direxpand\b'durumunda Bash bazı gelecekteki sürümü veya çatal bir alt dize olarak bu içeren bir seçeneği vardır ve uzaklaşmaların direxpand. Bu özel durumda olası değildir, ancak sağlam olmanın maliyeti yoktur.
Gilles 'SO- kötü olmayı bırak'

Teşekkürler Luciano. Kendi sorumu cevaplamak istedim, ancak düzenlemelerim akran değerlendirmesinden geçtikten sonra cevabınızı kabul edeceğim. Belki de bunları kendiniz onaylayabilirsiniz?
TheDudeAbides

4
Bash, belirli kabuk seçeneklerinin sorgulanmasına izin verir, böylece biri kullanılabilir [ -z "$(shopt -po direxpand 2>&-)" ] || shopt -s direxpand. Normal ifade sorunu yok! :-)
David Foerster

@DavidFoerster Mantığı tersine çevirirdim: [ -n "blah" ] && shopt blahİfade etme şekliniz, "direxpand desteklenmiyorsa, o şeyi yapma" diyorsunuz.
Zengin

1
@Rich: Kabuk betiklerimin çoğu set -eüstte, bu yüzden kısa yol mantığını bu şekilde kullanma eğilimindeyim.
David Foerster

16

Hataları yönlendirme konusunda neyin yanlış olduğunu göremiyorum /dev/null. Kodunuzun sağlam olmasını istiyorsanız set -e, ortak deyimi kullanın … || true:

shopt -s direxpand 2>/dev/null || true

Seçenek yoksa bazı yedek kod çalıştırmak istiyorsanız, aşağıdakilerin dönüş durumunu kullanın shopt:

if shopt -s direxpand 2>/dev/null; then
   # the direxpand option exists
else
   # the direxpand option does not exist
fi

Ancak hatayı yeniden yönlendirmekten gerçekten hoşlanmıyorsanız, introspection gerçekleştirmek için tamamlama mekanizmasını kullanabilirsiniz. Bu, programlanabilir tamamlanmayan bash ≤ 2.03'e sahip antika makineleriniz olmadığını varsayar.

shopt_exists () {
  compgen -A shopt -X \!"$1" "$1" >/dev/null
}
if shopt_exists direxpand; then
  shopt -s direxpand
fi

Bu yöntem, Cygwin gibi bazı ortamlarda yavaş olan çatallanmayı önler. Açıkçası 2>/dev/null, bunu performansta yenebileceğinizi sanmıyorum.


Yani değil gibi beynim gitti ettik nerede, ancak compgenönerinin. İşte orada üniversite düzeyi şeyler! Adresine yönlendirmeyi kullanmak /dev/nullyalnızca kişisel bir tercihtir. Eğer mantıklıysa affetmek yerine izin istemekten hoşlanır mıyım? :)
thedudeabides

Bash programlanabilir tamamlanmasında tamamen beklenmedik bir eğitim için +1, bu da beni ne anlama compgen -A shopt -X ...geldiğini deşifre etmek için kılavuza gitmeye zorladı .
thedudeabides

4
@TheDudeAbides Unix & Linux'tacompgen bu şekilde kullanmayı okudum , ilk kim önerdi bilmiyorum. (Programlanabilir tamamlanmadan önce ana kabuğum olarak bash'ı kullanmayı bıraktım.) Programlamada, izin istemek genellikle kötü bir fikirdir çünkü izin kontrolünün, kodlama nedeniyle gerçekte yaptığınızla eşleşmemesi riski vardır hata veya çünkü (burada oldukça sen sensin kontrol düşüncelerinizi kontrol edilmez) bunu kullanmadan önce değiştiğini checked neyi .
Gilles 'SO- kötü olmayı bırak

5

Bash'in belirli bir büyük / küçük / yama sürümünde belirli bir shoptseçeneğin bulunduğundan emin olduğunuzda , koşulu koşullu olarak etkinleştirmek için $BASH_VERSIONdeğişkeni veya öğeleri inceleyebilirsiniz $BASH_VERSINFO[].

İşte Bash 4.2.29 veya üstü için bir test , 4.2 serisine direxpand ilk tanıtılan sürüm :

if [[ $BASH_VERSION == 4.2.* && ${BASH_VERSINFO[2]} -ge 29 ]] ||
   [[ ${BASH_VERSINFO[0]} -eq 4 && ${BASH_VERSINFO[1]} -ge 3 ]] ||
   [[ ${BASH_VERSINFO[0]} -ge 5 ]]; then
    shopt -s direxpand
fi

Düzenleme: Açık olmak gerekirse, bu sadece giriş betiklerinizden gelen bir hata mesajını görmezden gelmek için gülünç aşırı mühendisli bir çözümdür, ama ne olursa olsun, benim kendi düzenleme için bunu belgelemek istiyorum.

Etrafında parantez Not , edilir gereklidir ve kullanımını ve (yerele bağımlı) sözcüksel karşılaştırmalar yerine tamsayı yapmak. Eğer belirtilmemişse, operatörün RHS'si , burada belirtildiği gibi Bash / koşullarında "ekstglob" paternleri olarak ele alınır ve bu , regex'in IMO'sundan daha estetik bir "karşılaştırma" karşılaştırması yapar.${BASH_VERSINFO[index]}-eq-gt==[[]]

$BASH_VERSINFODizi sen çıkışında görürdük tüm bilgileri içerir bash --version:

bash --version | head -1
# result:
# GNU bash, version 4.3.48(1)-release (x86_64-pc-linux-gnu)

declare -p BASH_VERSINFO
# result:
# declare -ar BASH_VERSINFO='([0]="4" [1]="3" [2]="48" [3]="1" [4]="release" [5]="x86_64-pc-linux-gnu")'

O zaman değil belgelerine açıkça shopthangi Bash sürümü (ler) destekli veya davranışlarını değiştirdi oldu Luciano önerdiği yöntem gayet:

# note the '-q' so that the matched pattern isn't actually printed
shopt | grep -q direxpand && shopt -s direxpand

... Gilles'in sadece hatayı görmezden gelmeyi önerdiği çözüm ( shopt -s direxpand 2>/dev/null) ve belki de $?kesinlikle gerekli olup olmadığını kontrol etmek.

Kaynaklar: 1 , 2 , 3
İlgili okuma: Set and Shopt - Neden İki?


Ayrıca böyle bir şey kullanmak mümkün olabilir if [[ $BASH_VERSION > 4.3 ]];(maçları 4.3.0, 5.0vb, aynı zamanda 4.3.0-alphabilmiyorum sonradan gerçeği konularda eğer..)
ilkkachu

Merhaba @ilkkachu. Bash v5.x dosyasını düzenlediğiniz için teşekkür ederiz. direxpandSeçenek olsa Bash 4.2 için gerçekten kullanılabilir; Bunu çalıştırarak v4.2.53'te bir Docker görüntüsü ile doğruladım docker run --rm bash:4.2 bash -c shopt | grep direxpand(ve iyi bir ölçü için gerçekten v4.1.17'de çalışarak mevcut olmadığınıdocker run --rm bash:4.1 bash -c shopt | grep direxpand ).
TheDudeAbides

ah tamam, 4.2.0orada çalışmadığı gerçeğini test ettim ve tökezledim. Değişiklik günlüğü eklediğinden de bahseder bash-4.3-alpha. Ben o zaman bu ${BASH_VERSINFO[2]}konuda kesin olup olmadığını kontrol etmek gerekir, ama hangi nokta sürüm ekledi bilmiyorum ...
ilkkachu

Bence Gilles'in yukarıda bahsettiği noktayı ispatladık; Aslında, kabuk seçeneğini etkinleştirmeyi denemek ve daha sonra desteklenmiyorsa hatayla uğraşmak (veya bastırmak) daha iyidir.
thedudeabides
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.