Ksh sürümünü nasıl güvenli bir şekilde alabilirim?


12

Ksh sürümünü ksh betiğinden nasıl güvenli bir şekilde alabilirim?

Ben var aşağıdaki çözümleri görüldü :

  1. ksh --version
  2. echo ${.sh.version}
  3. echo $KSH_VERSION

Ve doğru koşullar göz önüne alındığında, bunların her biri doğru çalışır. Ancak, mükemmel olmayan davayı önemsiyorum.

Özellikle, ksh'ın daha eski sürümlerine sahip, birlikte çalıştığım için, işlevlerimde ciddi ölçüde işlevsel olmayan birkaç makine var. Her neyse, sürümü (programlı olarak) kontrol etmek istememin nedeni, ksh sürümünün daha az yetenekli sürümlerden biri olup olmadığını görmek; ve eğer öyleyse, daha az harika kodlu bir şube yürütmek istiyorum.

Ancak, sorunlu makinelerde, kabuğun beceriksizliği sürümü kontrol etmeye uzanıyor ...

  • Denersem ksh --version, hiçbir şey yazdırmaz ve yeni bir örneğini açar ksh!
  • Eğer denersem echo ${.sh.version}, bunu kshatılamayan bir sözdizimi hatası olarak kabul eder 2> /dev/null.

    $ echo ${.sh.version} 2> /dev/null  
    ksh: ${.sh.version}: bad substitution
  • Tabii ki echo $KSH_VERSIONiyi çalışıyor gibi görünüyor - yani çökmeyecek - bu makinelerde boş. Ayrıca, gördüm bir yerlerdeKSH_VERSION sadece tarafından ayarlanır pdksh.

Sorular:

  • kshProgramlı olarak sürümü güvenli bir şekilde nasıl kontrol edebilirim ? Buradaki amacım için, gerçek sürüm numarasının ne olduğu umurumda değil, sadece eski bir sürümü olsun ksh.
  • $KSH_VERSIONyeterince iyi? Yani boşsa, kshmutlaka eski bir versiyon mu? Bu diğer forum, daha yeni sürümleri için bile ayarlanamayacağı doğru muydu ksh?
  • Bunu kontrol etmenin bir yolu yok mu?

1
Daha az müthiş kodu olan tek bir kod değil, iki kod yolu mu istiyorsunuz?
Thorbjørn Ravn Andersen

@ ThorbjørnRavnAndersen istemi ile ilgili. .Kshrc dosyamda, tcsh ve zsh istemlerinin pwd kısaltma işlevini simüle eden bir işlevim var ve PS1bu işlevi kullanmak için ayarladım . Ancak, Eski Ksh desteklemez $()içinde PS1. Eğer ksh'ın modern bir versiyonu ise, PS1yarattığım fonksiyonu kullanmak istiyorum ; eski sürüm ise, sadece kullanıyorum $PWD.
Sildoreth

Peki, yapılandırma dosyanızın (belki de biri diğerinden oluşturulmuş) iki sürümüne sahip olabilir ve daha sonra uygun sürümü söz konusu makineye dağıtabilirsiniz?
Thorbjørn Ravn Andersen

Başka bir yaklaşım sadece "Bu sadece sorunu olan bu özel makine - bir dosya veya ortam değişkeni ya da sadece burada var olan başka bir şey (muhtemelen AIX ya da bir şey) bulmak ve bunun için test" demek olabilir.
Thorbjørn Ravn Andersen

Yanıtlar:


7

Bence bu .sh.versionATT ksh 93'ün ilk versiyonundan beri var. Pdksh veya mksh'de mevcut değil. Yana ${.sh.version}ksh93 dışındaki kabuklarda bir yazım hatasıdır, bir kabuktaki bunun için testi sarın ve arkasında onu korumak eval.

_sh_version=$(eval 'echo "${.sh.version}"' 2>/dev/null) 2>/dev/null
case $_sh_version in
  '') echo "This isn't ATT ksh93";;
  
esac

KSH_VERSION kamu malı ksh klonunda (pdksh) başladı ve 2008 yılında ksh93t ile nispeten yakın zamanda gerçek Korn kabuğuna eklendi.

Bir sürüm numarasını test etmek yerine, size keder veren özelliği test etmelisiniz. Çoğu özellik, bir alt kabuktaki bazı yapıları deneyerek test edilebilir ve bir hatayı tetikleyip tetiklemediğini görebilir.


Subshell kullanırken hiçbir fark görmüyorum. Hala ${.sh.version}uzlaştırılamayan bir sözdizimi hatası gibi davranır . Aldığım mesaj bad substitution.
Sildoreth

@sil Bir alt kabuk kullanmanın amacı hatayı yakalamaktır. Hataları /dev/nullçıkış durumuna yönlendirin ve yok sayın.
Gilles 'SO- kötü olmayı bırak'

Ne dediğini anlıyorum. Söylediğim, hatanın yeniden yönlendirilmemesi. Her zaman konsola yazdırılır. Bunu Solaris, AIX ve HP-UX'de denedim; ve ksh bu davranışı hepsinde gösterir.
Sildoreth

@Sildoreth Ah. Yalnızca Linux'ta test yapardım ve şu anda test etmek için bu işletim sistemlerinden hiçbirine sahip değilim. Daha eval '_sh_version=$(echo "${.sh.version}")' 2>/dev/nulliyi çalışıyor mu?
Gilles 'SO- kötü olmayı bırak'

Biraz daha iyi. Solaris ve HP-UX'te mükemmel çalışır. AIX için, komut satırında çalışır, ancak bir kabuk işlevine yerleştirmeye çalışırsam merakla tekrar başarısız olmaya başlar.
Sildoreth

6

KSH_VERSIONksh9393t sürümünden önce uygulanmadı . Bu hale getirileceğini mksh, pdksh, lksh. Dolayısıyla, sürümünü kontrol etmek için kshşu adımları deneyebiliriz:

Bunları aklımda tutarak:

case "$KSH_VERSION" in
  (*MIRBSD*|*PD*|*LEGACY*) printf '%s\n' "$KSH_VERSION" ;;
  (*) [ -z "$ERRNO" ] && printf '%s\n' "${.sh.version}" || echo ksh88/86 ;;
esac

Bu niçin $KSH_VERSIONönce boş değilse kontrol etmiyor ? Ubuntu makinemde bu "ksh93" yazdı, henüz KSH_VERSIONayarlanmış.
Sildoreth

Daha önce yürütülen bazı kodlar (örneğin: .kshrc) KSH_VERSION değişkenini rastgele bir değerle değiştirdiğinde bu başarısız olur.
jlliagre

@jlliagre: Hayır, komut dosyası olarak çalıştırıldığı için okumuyor .kshrc.
cuonglm

Eğer ENVdeğişken ayarlanır (ve tipik bunun için ayarlanır ~/.kshrc), senaryo kesinlikle okuyacak .kshrcdosyayı. Tabii ki, bir komut dosyasının sahte bir KSH_VERSION ayarlaması oldukça garip olurdu, ancak yine de bu mümkündür, tıpkı ilk satırda belirtilen koddan farklı bir yorumlayıcıyla açıkça bir komut dosyası yürütmek olası bir durumdur.
jlliagre

@jlliagre: Değiştirebilseniz bile, başvurduğunuzda segfault elde edersiniz KSH_VERSION. Ve de mksh, pdksh, lksh, KSH_VERSIONsalt okunur olarak işaretlenmiş.
cuonglm

5

"Gerçek" kshsürümler (yani AT&T tabanlı) için bu komutu kullanıyorum:

strings /bin/ksh | grep Version | tail -2 

İşte olsun çeşitli çıktı:

Orijinal ksh:

@(#)Version M-11/16/88i

dtksh;

@(#)Version 12/28/93
Version not defined

Modern ksh93:

@(#)$Id: Version AJM 93u+ 2012-08-01 $

İçin pdksh/ msh kshklonlar ve modern AT & T kshde sürümleri, burada bir şeydir eserler olduğunu:

$ mksh -c 'echo $KSH_VERSION'
@(#)MIRBSD KSH R50 2015/04/19

Düzenle:

Test edilen ksh ikilisine giden yolu bilmeden değil, bir senaryo içinden yapmayı sorduğunuzu gözden kaçırdım.

kshDesteklenen özelliklerin değil, kullanılmış sürümün gerçekten olmasını istediğinizi varsayarsak , bunu yalnızca stringsen azından Linux ve Solaris'te çalışması gereken komutu kullanarak yapmanın bir yolu vardır :

echo $(for i in $(find /proc/$$ ! -type d ! -name "pagemap" | 
  grep -v "/path/" | grep -v "/fd/" ) ; do
  strings $i | egrep "([V]ersion|[K]SH_VERSION).*[0-9]" | sort -u
done 2>/dev/null)

Bu yöntemin /procmonte edilemeyeceği gibi güvenilir olmadığını ve kesinlikle başka zayıflıkların olduğunu unutmayın. Diğer Unix işletim sistemlerinde test edilmemiştir.


Bu ayırt edilmez lkshve pdkshDebian Jessie.
cuonglm

@cuonglm Test edecek Jessie yok. Şunu musunuz lkshve pdkshonların dan dizildi edilemez KSH_VERSION?
jlliagre

Hayır strings. KSH_VERSIONkesinlikle olabilir.
cuonglm

@cuonglm Belirsiz olsaydım özür dilerim. "" Gerçek " kshsürümler için" yazdığımda , AT&T ksh olmayan klonları pdksh, mkshve lksh.
jlliagre

stringsBazı ksh ikili dosyalar üzerinde çalıştırmak kötü bir fikir çünkü senaryonuzu çalıştıranın bu olup olmadığını bilmiyorsun. Belki senaryonuz /usr/local/bin/kshya /home/bob/bin/kshda ya da /bin/shya /usr/posix/bin/shda ... tarafından yönetiliyor ...
Gilles 'SO- kötü olmayı bırak'

2

Bir komut dosyası yazarken , ksh'ın yerleşik komut seçeneğinin eski sürümlerinde desteklenmediğini kshfark ettim . Ve bu, Solaris, AIX, HP-UX ve Linux dahil olmak üzere kontrol ettiğim tüm sistemler için geçerli gibi görünüyor.-awhenceksh

İşte bir ksh işlevi olarak çözüm:

is_modern_ksh() {
  if whence -a whence > /dev/null 2>&1 ; then
    return 0 #success -> true
  fi
  #Else the call to `whence` failed because `-a` is not supported
  return 1 #failure -> false
}

İşte nasıl kullanılacağı:

if is_modern_ksh ; then
  echo "You're using a MODERN version of ksh. :)"
else
  echo "You're using an OLD version of ksh. :("
fi

Neden kullanmıyorsun ${.sh.version}?
cuonglm

@cuonglm çünkü yapamam. Gilles'in cevabı hakkındaki yorumlara bakın .
Sildoreth

ne yazık ki whenceZsh vardır-a
Greg A. Woods

@ GregA.Woods, bu işlev özellikle ksh içindir. İşlev tanımı .kshrc biçiminde olur ve zsh gibi diğer mermiler için bile mevcut olmaz. zsh, whenceksh veya sürümüne bağlı olmayan kendi yerleşik komutuna sahiptir. Tamamen farklı bir kabuk olan zsh'nin içindeki ksh'ın eski bir sürüm olup olmadığını neden kontrol etmek istediğinizi bile bilmiyorum.
Sildoreth

Varsayımlarınızla ilgili bir sorun var: Zsh genellikle /bin/kshDebian Linux'ta bir bağlantı ile kurulur . Şimdi orada kullanmıyorum (ve şu anda giriş kabuğumu kontrol etmek için değiştiremiyorum), bu yüzden okuyup okumadığını bilmiyorum .kshrc, ama şüpheliyim.
Greg A. Woods

1

CTRL+ ALT+V

veya

ESC, CTRL+V

Kullandığınız KSH sürümünü etkileşimli olarak belirlediği sürece tipik olarak çok güvenilir olduğunu kanıtladınız, ancak komut dosyalarını yazmanın daha zor olduğu kanıtlanmıştır.


1
AIX ksh 88f versiyonu için çalışan tek model buydu.
Jeff Schaller

1
set -o viVi-benzeri olacak şekilde ayarlamak için koştuktan sonra, <kbd> ESC </kbd>, <kbd> CTRL </kbd> + <kbd> V </kbd> seçeneği var . Ondan önce ya da + o vi ya da -o emacs ile bana göstermezdi. Openbsd 6.1 üzerinde PD KSH v5.2.14 99/07 / 13.2
bgStack15

0

$ {. Sh.version} kullanarak temel sorun, ksh88 sıfır dışında bir çıkış kodu ile sadece durur olduğunu düşünüyorum.

Bu yüzden benim çözümüm $ {. Sh.version} 'a başvuran kodu bir alt kabuğa koymak, sonra alt kabuğun sıfırdan çıkıp çıkmadığını ve alt kabuğun sürümlerinde çalışacak kodu olup olmadığını test etmek. $ {. sh.version} 'a gönderme yapan ksh çalışır. Daha sonra dönüş kodunu tersine çeviren başka bir işlev tarafından çağrılan bir işleve sarılması, böylece son çağrı doğru olup olmadığını kontrol eder.

function is_oldksh
{
    (test -n ${.sh.version}) 2>/dev/null
}

function oldkshtest
{

    is_oldksh || return 0 && return 1
}

oldkshtest && echo "old ksh" || echo "new ksh"

Bunu AIX ve Oracle Enterprise Linux 5 & 6'da ksh88, ksh93 ve pdksh ile çalıştırdım.

Pete


1
modern AT&T Ksh hala tedarik etmektedir .sh.version(aslında KSH_VERSIONetkili bir takma addır ). Ayrıca bazı kabuklar, örneğin NetBSD sh, karşılaştıktan sonra okumayı durdurur ${.sh.version}ve hiçbir yönlendirme komut dosyasını çalıştırmaya devam edemez.
Greg A. Woods

0

Aşağıdakiler, gerçek bir orijinal Bourne kabuğu ( ve bunu yapmak, testifadeyi eski sürümler için uyarlamayı gerektirebilir ....

Zeyilname:

Şimdi bunu harici (ve daha modern) bir testprogramla da Heirloom Bourne Shell ile başarıyla test ettim .

is_attksh()
{
    # ksh93
    _sh_version=$(eval 'echo "${.sh.version}"' 2>/dev/null)
    # pdksh only
    _opt_login=$(set -o | grep login)

    test -n "${_sh_version}" -o \( -z "${_opt_login}" -a -n "${_}" -a -n "${ERRNO}" -a -n "${FCEDIT}" -a -n "${PS3}" \)
}
is_attksh && echo "AT&T Ksh${_sh_version:+: }${_sh_version:- (probably ksh88 or ksh86)}" || echo "not real ksh"

is_zsh()
{
    test -n "${ZSH_VERSION}"
}
is_zsh && echo "Zsh: ${ZSH_VERSION}" || echo "not zsh"

Neden bu işlevi ksh olmayan mermiler için çalıştırmak istersiniz? Eğer bash veya zsh'de bir script çalıştırıyorsanız, ksh asla devreye girmez. Dahası, ${.sh.version}çözümün bir parçası olamayan başkalarının cevapları aracılığıyla zaten kurulmuştur , çünkü ksh'ın belirli sürümleri - orijinal yazının söz konusu sürümleri - sözdiziminde ölümcül hata.
Sildoreth

Söylediğim gibi, gösterdiğim işlev, "ölümcül" hatalar veren ksh sürümleri ve aynı şeyi yapan Ash sürümleriyle test edildi.
Greg A. Woods

Yazdığım komut dosyalarının taşınabilir olması ve herhangi bir yetenekli kabuk tarafından çalıştırılması amaçlanmıştır. Ayrıca, başka bir yerde söylediğim gibi, bazı insanlar mutlaka Zsh'ı Ksh olarak kullandıklarını bilmeyeceklerdir, çünkü 'ksh' yazdıklarında Zsh ikili dosyası çağrılacaktır (argv [0] ile "ksh" olarak).
Greg A. Woods

Bu, nereden geldiğinize ışık tutuyor. Ancak, bu gerçekçi olmayan bir gereklilik gibi görünüyor. Tipik olarak, bir Unix geliştiricisi "taşınabilir" dediğinde, "bu kod herhangi bir kabukta çalışacak " anlamına gelmez, "bu herhangi bir sistemde çalışacaktır" anlamına gelir . Ve başka bir kabuk için yazılmış bir komut dosyasını yürütmeniz gerekiyorsa, bu tamamen yasaldır; betiğinizdeki diğer kabuğun etkileşimli olmayan bir örneğini başlatmanız yeterlidir. Bunu gündeme getiriyorum çünkü iyi kodlama uygulamalarını teşvik etmek istiyorum. Bu çözüm işinize yarıyorsa harika. Ama başkalarına daha basit bir yaklaşım benimsemelerini tavsiye ederim.
Sildoreth

1
Kuşkusuz, geriye dönük uyumluluğu geçmişe doğru sürükleme çabaları oldukça saçmadır. Eski AT&T Ksh ve Unix Sh'ın sadece bazı özelliklerin tarihini ve evrimini daha iyi anlamak ve bazı şeylerin nasıl olduğuyla ilgili hafızamı yenilemek için kendi kişisel isteğimi tatmin etmek için sadece derlenmiş versiyonları derledim (genellikle beni şaşırtıyor, çünkü işler genellikle çok fazla " hatırladığımdan daha iyi "olsa da, bazen çok daha kötüydüler).
Greg A. Woods
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.