मैं सुरक्षित रूप से ksh का संस्करण कैसे प्राप्त कर सकता हूं?


12

मैं सुरक्षित रूप से ksh स्क्रिप्ट के भीतर ksh का संस्करण कैसे प्राप्त कर सकता हूं ?

मैंने निम्नलिखित उपाय देखे हैं :

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

और सही परिस्थितियों को देखते हुए, इनमें से प्रत्येक सही ढंग से काम करता है। हालांकि, मैं गैर-परिपूर्ण मामले की परवाह करता हूं।

विशेष रूप से, ऐसी कई मशीनें हैं जिनके साथ मैं काम करता हूं, जिनके पास ksh के पुराने संस्करण हैं, मेरे उद्देश्यों के लिए, कार्यक्षमता में गंभीर कमी है। वैसे भी, मैं संस्करण की जांच करना चाहता हूं (प्रोग्रामिक रूप से) यह देखना है कि क्या ksh संस्करण कम सक्षम संस्करणों में से एक है; और यदि हां, तो मैं कम भयानक कोड वाली एक शाखा को निष्पादित करना चाहता हूं।

हालाँकि, समस्याग्रस्त मशीनों पर, शेल की अशुद्धि संस्करण की जाँच में विस्तारित होती है ...

  • अगर मैं कोशिश करता हूं ksh --version, तो यह कुछ नहीं छापता है और एक नया उदाहरण खोलता है ksh!
  • यदि मैं कोशिश करता हूं echo ${.sh.version}, तो kshइसे एक वाक्यविन्यास त्रुटि के रूप में माना जाता है जिसे नहीं छोड़ा जा सकता है 2> /dev/null

    $ echo ${.sh.version} 2> /dev/null  
    ksh: ${.sh.version}: bad substitution
  • बेशक echo $KSH_VERSIONठीक काम करने के लिए प्रकट होता है - मेरा मतलब है कि यह दुर्घटना नहीं होगी - हालांकि इन मशीनों पर यह खाली है। इसके अलावा, मैंने कहीं ऐसा देखा जो KSH_VERSIONकेवल द्वारा निर्धारित किया गया हो pdksh

प्रशन:

  • मैं kshप्रोग्रामेटिक रूप से संस्करण को सुरक्षित रूप से कैसे जांच सकता हूं ? यहां मेरे उद्देश्यों के लिए, मुझे वास्तव में परवाह नहीं है कि वास्तविक संस्करण संख्या क्या है, बस यह एक पुराना संस्करण है या नहीं ksh
  • है $KSH_VERSIONकाफी अच्छा? मेरा मतलब है कि अगर यह रिक्त है, तो kshजरूरी एक पुराना संस्करण है? क्या यह अन्य मंच सही था कि इसे नए संस्करणों के लिए भी सेट नहीं किया जा सकता है ksh?
  • क्या यह जांचने का कोई तरीका नहीं है?

1
किसी भी कारण से आप दो कोड पथ चाहते हैं और कम भयानक कोड के साथ एक ही नहीं?
थोरबजोरन राव एंडरसन

@ ThorbjørnRavnAndersen इसे प्रॉम्प्ट के साथ करना होगा। मेरी .kscc फ़ाइल में, मेरे पास एक फंक्शन है जो tcsh और zsh प्रॉम्प्ट की pwd-संक्षिप्ताक्षर कार्यक्षमता को अनुकरण करता है, और मैं PS1इस फ़ंक्शन का उपयोग करने के लिए सेट करता हूं । हालाँकि, पुरानी ksh समर्थन नहीं करता $()है PS1। तो अगर यह ksh का एक आधुनिक संस्करण है, तो मैं अपने द्वारा PS1बनाए गए फ़ंक्शन का उपयोग करना चाहता हूं; यदि यह पुराना संस्करण है, तो मैं अभी उपयोग करता हूं $PWD
सिल्डोरेथ

ठीक है, आपकी कॉन्फ़िगरेशन फ़ाइल के दो संस्करण हो सकते हैं (शायद दूसरे से उत्पन्न) और फिर प्रश्न में मशीन को उपयुक्त संस्करण वितरित करें?
थोरबजोर्न रेवन एंडरसन

एक अन्य दृष्टिकोण केवल यह कहने के लिए हो सकता है "यह केवल यह विशेष मशीन है जिसमें समस्या है - मैं एक फ़ाइल या पर्यावरण चर या कुछ और ढूंढूंगा जो केवल यहां मौजूद है (शायद एआईएक्स या कुछ भी) और इसके बजाय इसके लिए परीक्षण करें"।
थोरबजोरन रावन एंडरसन

जवाबों:


7

मुझे लगता है कि .sh.versionएटीटी ksh 93 के पहले संस्करण के बाद से कभी भी अस्तित्व में है। यह pdksh या mksh में उपलब्ध नहीं है। चूँकि ${.sh.version}ksh93 के अलावा गोले में एक वाक्यविन्यास त्रुटि है, इसके लिए परीक्षण को एक उप-भाग में लपेटें और इसे पीछे की रक्षा करें 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 सार्वजनिक डोमेन ksh क्लोन (pdksh) में शुरू हुआ, और वास्तविक Korn खोल में अपेक्षाकृत हाल ही में जोड़ा गया, 2008 में ksh93t के साथ।

एक संस्करण संख्या के लिए परीक्षण करने के बजाय, आपको उस विशिष्ट सुविधा के लिए परीक्षण करना चाहिए जो आपको दुःख दे रही है। अधिकांश विशेषताओं को एक उपधारा में कुछ निर्माण की कोशिश करके परीक्षण किया जा सकता है और देखें कि क्या यह एक त्रुटि को ट्रिगर करता है।


मुझे किसी सबशेल का उपयोग करते समय कोई अंतर नहीं दिखता है। यह अभी भी ${.sh.version}एक सिंटैक्स त्रुटि के रूप में व्यवहार करता है जिसे समेटा नहीं जा सकता। मुझे जो संदेश मिला है bad substitution
सिल्डोरेथ

@ एससीएल एक उपखंड का उपयोग करने का बिंदु त्रुटि को पकड़ना है। /dev/nullबाहर निकलने की स्थिति की त्रुटियों को अनुप्रेषित करें ।
गाइल्स का SO- बुराई पर रोक '

तुम्हारे द्वारा कहा गया मेरी समझ में आ रहा है। मैं जो कह रहा हूं वह यह है कि त्रुटि अनुप्रेषित नहीं करती है। यह हमेशा कंसोल को प्रिंट करता है। मैंने Solaris, AIX और HP-UX में यह कोशिश की; और ksh उन सभी में इस व्यवहार को प्रदर्शित करता है।
सिल्डोरेथ

@ सिल्डोरथ आह। मैंने केवल लिनक्स पर परीक्षण किया था, और मेरे पास अब परीक्षण करने के लिए इनमें से कोई भी OSes नहीं है। eval '_sh_version=$(echo "${.sh.version}")' 2>/dev/nullकोई बेहतर काम करता है?
गिलेस एसओ- बुराई को रोकना '

यह थोड़ा बेहतर है। यह सोलारिस और एचपी-यूएक्स में पहले से काम करता है। AIX के लिए, यह कमांड लाइन पर काम करता है लेकिन अगर मैं इसे शेल फंक्शन में रखने की कोशिश करता हूं तो उत्सुकता से फिर से असफल होने लगता है।
सिल्डोरेथ

6

KSH_VERSIONksh93संस्करण 93t से पहले लागू नहीं किया गया था । यह में स्थापित किया जाएगा mksh, pdksh, lksh। तो के संस्करण की जाँच के लिए ksh, हम इन चरणों की कोशिश कर सकते हैं:

  • जाँच हो रही है KSH_VERSIONपता लगाने के लिए mksh, pdksh,lksh
  • यदि पहला चरण विफल हो जाता है, तो एक ऐसी सुविधा का प्रयास करें जो बीच में भिन्न हो ksh93और ksh88/86( डेविड कोर्न हमें दिखाएं )।

इन बातों को ध्यान में रखते हुए, मैं जाऊंगा:

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

यदि $KSH_VERSIONपहले गैर-रिक्त है तो यह जांच क्यों नहीं करता है? मेरे उबंटू मशीन पर, यह "ksh93" प्रिंट करता है, फिर KSH_VERSIONभी सेट है।
सिल्डोरेथ

यदि कुछ पहले निष्पादित कोड (जैसे: .kshrc) ने कुछ यादृच्छिक मान के साथ KSH_VERSION चर को छेड़छाड़ की तो यह विफल हो जाएगा।
jlliagre

@ जेलीग्रे: नहीं, क्योंकि यह एक स्क्रिप्ट के रूप में चलाया गया था, यह नहीं पढ़ा .kshrc
कोउंगलम

यदि ENVचर सेट है (और आमतौर पर इसे सेट किया जाता है ~/.kshrc), तो स्क्रिप्ट निश्चित रूप से .kshrcफ़ाइल को पढ़ेगी। बेशक, एक स्क्रिप्ट के लिए एक बोगस KSH_VERSION सेट करना काफी अजीब होगा, लेकिन यह फिर भी संभव है, ठीक उसी तरह जैसे किसी स्क्रिप्ट को अपनी पहली पंक्ति में निर्दिष्ट एक से एक अलग व्याख्याकार के साथ स्पष्ट रूप से निष्पादित करना एक संभावित स्थिति है।
जुलियाग्रे

@ जेलीग्रे: यहां तक ​​कि आप इसे बदल सकते हैं, जब आप संदर्भ लेंगे तो आपको सेगफॉल्ट मिलेगा KSH_VERSION। और में mksh, pdksh, lksh, KSH_VERSIONकेवल पढ़ने के रूप में चिह्नित किया गया है।
कोउंगलम

5

"वास्तविक" kshरिलीज़ (यानी एटी एंड टी आधारित) के लिए, मैं इस कमांड का उपयोग करता हूं:

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

यहां मुझे विभिन्न आउटपुट मिलते हैं:

मूल ksh:

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

dtksh;

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

आधुनिक ksh93:

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

के लिए pdksh/ msh kshक्लोन और आधुनिक एटी एंड टी kshसंस्करण भी है, यहाँ कुछ है कि काम करता है:

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

संपादित करें:

मैंने अनदेखा किया कि आप इसे स्क्रिप्ट के अंदर से करने के बारे में पूछ रहे थे, न कि परीक्षण किए गए ksh बाइनरी के लिए रास्ता जानने से।

यह मानते हुए कि आप वास्तव में kshउपयोग किए गए संस्करण को चाहते हैं , न कि सुविधाओं का समर्थन करता है, यहां केवल stringsकमांड का उपयोग करके ऐसा करने का एक तरीका है जो कम से कम लिनक्स और सोलारिस पर काम करना चाहिए:

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)

ध्यान दें कि यह विधि अविश्वसनीय /procनहीं है क्योंकि माउंट नहीं किया जा सकता है, और निश्चित रूप से अन्य कमजोरियां हैं। यह अन्य यूनिक्स ओएस पर अप्रयुक्त है।


यह डेबियन जेसी में lkshऔर उसके बीच अंतर नहीं करेगा pdksh
cuonglm

@cuonglm मेरे पास परीक्षण करने के लिए कोई जेसी नहीं है। क्या आपका मतलब है lkshऔर pdkshउनका हल नहीं निकाला जा सकता है KSH_VERSION?
जूलियाग्रे

नहीं, मेरा मतलब stringsउन पर चल रहा है । KSH_VERSIONनिश्चित रूप से कर सकते हैं।
cuonglm

@cuonglm क्षमा करें यदि मैं अस्पष्ट था। जब मैंने «" वास्तविक " kshरिलीज के लिए« लिखा था, तो मैं स्पष्ट रूप से गैर एटी एंड टी केएचएस क्लोन जैसे pdksh, mkshऔर lksh
जुलियाग्रे

stringsकुछ ksh बाइनरी पर चलना एक बुरा विचार है क्योंकि आप नहीं जानते कि क्या यह वही है जो आपकी स्क्रिप्ट चला रहा है। हो सकता है कि अपनी स्क्रिप्ट द्वारा चलाया जा रहा है /usr/local/bin/kshया /home/bob/bin/kshया /bin/shया /usr/posix/bin/shया ...
गाइल्स 'तथाकथित बंद किया जा रहा बुराई'

2

जब मैं एक स्क्रिप्ट लिख रहा था ksh, मैंने देखा कि -aksh की अंतर्निहित whenceकमांड का विकल्प पुराने संस्करणों में समर्थित नहीं है ksh। और यह मेरे द्वारा जाँच की गई सभी प्रणालियों पर सही प्रतीत होता है, जिसमें सोलारिस, एआईएक्स, एचपी-यूएक्स और लिनक्स शामिल हैं।

तो यहाँ एक ksh फ़ंक्शन के रूप में समाधान है:

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
}

और यहाँ इसका उपयोग कैसे करना है:

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

आप उपयोग क्यों नहीं करते ${.sh.version}?
cuonglm

@cuonglm क्योंकि मैं नहीं कर सकता। गाइल्स के उत्तर पर टिप्पणियों को देखें ।
सिल्डोरेथ

दुर्भाग्य से whenceZsh में है-a
ग्रेग ए। वुड्स

@ ग्रेग.वूड्स, यह फंक्शन खासतौर पर ksh के लिए है। फ़ंक्शन की परिभाषा .kshrc में जाएगी और इसलिए अन्य गोले जैसे zsh के लिए भी मौजूद नहीं होगी। zsh का अपना अंतर्निहित whenceकमांड है जो कि ksh या उसके संस्करण से किसी भी तरह से जुड़ा नहीं है। मुझे यह भी नहीं पता है कि अगर zsh के एक पुराने संस्करण से ksh एक पुराना संस्करण है, जो पूरी तरह से अलग शेल है, तो आप इसकी जांच क्यों करेंगे।
सिल्डोरेथ

आपकी मान्यताओं के साथ एक समस्या है: Zsh अक्सर एक लिंक के साथ स्थापित होता है /bin/ksh, जैसे डेबियन लिनक्स पर। अब मैं वहां इसका उपयोग नहीं करता (और फिलहाल मैं अपने लॉगिन शेल को जांचने के लिए नहीं बदल सकता), इसलिए मुझे नहीं पता कि यह पढ़ता है .kshrcया नहीं, लेकिन मुझे इस पर संदेह है।
ग्रेग ए। वुड्स

1

CTRL+ ALT+V

या

ESC, CTRL+V

आमतौर पर जहाँ तक केएसएच आपके द्वारा उपयोग किए जा रहे संस्करण को निर्धारित करने के रूप में बहुत विश्वसनीय साबित हुआ है, हालांकि स्क्रिप्टिंग उन्हें अधिक कठिन साबित हुई है।


1
यह एकमात्र ऐसा था जिसने AIX ksh 88f संस्करण के लिए काम किया था।
जेफ स्कालर

1
मेरे पास काम set -o viकरने के लिए कीबाइंडिंग सेट करने के लिए चलाने के बाद <kbd> ESC </ kbd>, <kbd> CTRL </ kbd> + <kbd> V </ kbd> विकल्प मिला । इससे पहले, या + ओ vi या -o emacs के साथ, यह बस मुझे नहीं दिखाएगा। PD KSH v5.2.14 99/07 / 13.2
ओपनबेड्स

0

मुझे लगता है कि $ {। Sh.version} का उपयोग करने के साथ मूलभूत समस्या यह है कि ksh88 सिर्फ एक गैर-शून्य निकास कोड के साथ बंद हो जाता है।

तो मेरा समाधान कोड को उप-शेल में $ {। Sh.version} के संदर्भ में रखना है, फिर यह देखने के लिए परीक्षण करें कि क्या उप-शेल गैर-शून्य से बाहर निकल गया है और उप-शेल में कोड है जो संस्करणों के संस्करणों पर काम करेगा ksh जहाँ $ {। sh.version} को संदर्भित करता है, काम करता है। इसे एक फ़ंक्शन में रैप करना जो फिर एक अन्य फ़ंक्शन द्वारा कॉल किया जाता है जो रिटर्न कोड को उलट देता है, ताकि अंतिम कॉल सही के लिए जाँच कर रहा हो।

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"

मैंने इसे AIX और Oracle Enterprise Linux 5 & 6 पर ksh88, ksh93 और pdksh के साथ चलाया है।

पीट


1
आधुनिक एटी एंड टी क्ष अभी भी आपूर्ति करता है .sh.version(वास्तव KSH_VERSIONमें प्रभावी रूप से इसके लिए एक उपनाम है)। इसके अलावा कुछ गोले, जैसे कि नेटबीएसडी श, बस मुठभेड़ के बाद पढ़ना बंद ${.sh.version}कर देते हैं और पुनर्निर्देशन की कोई भी राशि उन्हें स्क्रिप्ट चलाने के लिए नहीं रख सकती है।
ग्रेग ए। वुड्स

0

निम्नलिखित उन सभी शेलों के लिए यथोचित रूप से अच्छी तरह से काम करता है जो मैंने पुराने ksh88e और सामान्य Ksh क्लोनों की लगभग पूरी रेंज (हालांकि प्रत्येक का केवल एक संस्करण) सहित परीक्षण किया है, हालांकि मैंने अभी तक एक वास्तविक मूल बॉर्न शेल का परीक्षण नहीं किया है ( और ऐसा करने के testलिए पुराने संस्करणों के लिए अभिव्यक्ति को अपनाने की आवश्यकता हो सकती है ...।

परिशिष्ट:

मैंने अब इसका सफलतापूर्वक हीरलूम बॉर्न शेल के साथ परीक्षण किया है, हालांकि एक बाहरी (और अधिक आधुनिक) testकार्यक्रम के साथ।

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"

आप इस फ़ंक्शन को ksh नहीं होने वाले गोले के लिए क्यों चलाना चाहते हैं? यदि आप किसी स्क्रिप्ट को bash या zsh में चला रहे हैं, तो ksh कभी भी प्ले में नहीं आता है। इसके अलावा, यह पहले से ही दूसरों के उत्तरों के माध्यम से स्थापित ${.sh.version}किया गया है जो समाधान का हिस्सा नहीं हो सकते हैं क्योंकि ksh के कुछ संस्करण - जो संस्करण मूल पोस्ट के बारे में चिंतित थे - उस वाक्यविन्यास पर वस्तुतः त्रुटि।
सिल्डोरेथ

जैसा कि मैंने कहा, मेरे द्वारा दिखाए जाने वाले फ़ंक्शन को ksh के संस्करणों के साथ परीक्षण किया गया है जो "घातक" त्रुटियां देते हैं, साथ ही ऐश के संस्करण भी जो ऐसा करते हैं।
ग्रेग ए। वुड्स

मेरे द्वारा लिखी गई लिपियों का उद्देश्य पोर्टेबल होना और किसी भी सक्षम शेल द्वारा चलाया जाना है। इसके अलावा, जैसा कि मैंने कहीं और कहा, कुछ लोग जरूरी नहीं जानते होंगे कि वे Zsh का उपयोग Ksh के रूप में कर रहे हैं क्योंकि जब वे 'ksh' टाइप करते हैं तो Zsh बाइनरी ("ksh" के रूप में argv [0] के साथ) को आमंत्रित किया जाएगा।
ग्रेग ए। वुड्स

आप कहां से आ रहे हैं, इस पर प्रकाश डालते हैं। हालाँकि, यह एक अवास्तविक आवश्यकता की तरह लगता है। आमतौर पर, जब एक यूनिक्स डेवलपर "पोर्टेबल" कहता है, तो उनका मतलब यह नहीं है कि "यह कोड किसी भी शेल में चलेगा ", उनका मतलब है "यह किसी भी सिस्टम पर चलेगा "। और अगर आपको एक स्क्रिप्ट को निष्पादित करने की आवश्यकता है जो दूसरे शेल के लिए लिखा गया था, तो यह पूरी तरह से कानूनी है; बस अपनी स्क्रिप्ट में अन्य शेल का एक गैर-इंटरेक्टिव उदाहरण शुरू करें। मैं इसे ऊपर लाता हूं क्योंकि मैं अच्छी कोडिंग प्रथाओं को बढ़ावा देना चाहता हूं। यदि यह समाधान आपके लिए काम करता है, तो बढ़िया है। लेकिन मैं दूसरों को एक सरल दृष्टिकोण अपनाने की सलाह दूंगा।
सिल्डोरेथ

1
मोटे तौर पर अतीत में बहुत दूर तक अनुकूलता को पीछे खींचने के कोई भी प्रयास मूर्खतापूर्ण हैं। मैंने प्राचीन AT & T Ksh और Unix Sh के केवल संस्करणों को संकलित किया है ताकि कुछ विशेषताओं के इतिहास और विकास को बेहतर ढंग से समझने और चीजों की स्मृति को ताज़ा करने के लिए अपनी व्यक्तिगत इच्छा को पूरा करने के लिए (जो आमतौर पर मुझे आश्चर्यचकित करते हैं, क्योंकि चीजें अक्सर बहुत थीं " बेहतर है "मुझे याद है, हालांकि कुछ समय में वे भी बहुत खराब थे)।
ग्रेग ए। वुड्स
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.