Wie kann ich die Version von ksh sicher bekommen?

12

Wie kann ich die Version von ksh sicher aus einem ksh-Skript herunterladen?

Ich habe die folgenden Lösungen gesehen :

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

Und unter den richtigen Umständen funktioniert jede dieser Funktionen ordnungsgemäß. Ich interessiere mich jedoch für den nicht perfekten Fall.

Insbesondere gibt es mehrere Maschinen, mit denen ich arbeite und die ältere Versionen von ksh haben, denen für meine Zwecke die Funktionalität stark fehlt. Wie auch immer, ich möchte die Version (programmgesteuert) überprüfen, um festzustellen, ob die ksh-Version eine der weniger leistungsfähigen Versionen ist. und wenn ja, möchte ich einen Zweig mit weniger fantastischem Code ausführen.

Auf den problematischen Rechnern reicht die Unfähigkeit der Shell jedoch aus, die Version zu überprüfen ...

  • Wenn ich es versuche ksh --version, druckt es nichts und öffnet eine neue Instanz von ksh!
  • Wenn ich es versuche echo ${.sh.version}, wird kshdies als Syntaxfehler behandelt, der nicht verworfen werden kann 2> /dev/null.

    $ echo ${.sh.version} 2> /dev/null  
    ksh: ${.sh.version}: bad substitution
    
  • Natürlich echo $KSH_VERSIONscheint es gut zu funktionieren - ich meine, es wird nicht abstürzen - obwohl es auf diesen Maschinen leer ist. Auch habe ich irgendwo gesehen, dass KSH_VERSIONnur durch gesetzt wird pdksh.

Fragen:

  • Wie kann ich die Version von sicher kshprogrammgesteuert überprüfen ? Für meine Zwecke hier ist es mir eigentlich egal, wie die tatsächliche Versionsnummer lautet, nur ob es sich um eine veraltete Version von handelt ksh.
  • Ist $KSH_VERSIONgut genug Ich meine, wenn es leer ist, ist es dann kshnotwendigerweise eine veraltete Version? War das andere Forum korrekt, dass es möglicherweise nicht einmal für neuere Versionen von eingestellt wurde ksh?
  • Gibt es überhaupt keine Möglichkeit, dies zu überprüfen?
Sildoreth
quelle
1
Möchtest du aus irgendeinem Grund zwei Codepfade und nicht nur einen mit weniger großartigem Code?
Thorbjørn Ravn Andersen
@ ThorbjørnRavnAndersen hat es mit der Eingabeaufforderung zu tun. In meiner .kshrc-Datei habe ich eine Funktion, die die pwd-abkürzende Funktionalität von tcsh- und zsh-Eingabeaufforderungen simuliert, und ich habe mich für die PS1Verwendung dieser Funktion eingerichtet. Old ksh unterstützt jedoch nicht $()in PS1. Wenn es sich also um eine moderne Version von ksh handelt, möchte ich die PS1von mir erstellte Funktion verwenden. wenn es die alte version ist, benutze ich eben $PWD.
Sildoreth,
Nun, könnten Sie zwei Versionen Ihrer Konfigurationsdatei haben (möglicherweise eine aus der anderen generiert) und dann die entsprechende Version an die betreffende Maschine verteilen?
Thorbjørn Ravn Andersen
Ein anderer Ansatz könnte darin bestehen, einfach zu sagen: "Nur diese bestimmte Maschine hat das Problem - ich finde eine Datei oder Umgebungsvariable oder etwas anderes, das nur hier existiert (wahrscheinlich AIX oder sowas) und teste stattdessen darauf."
Thorbjørn Ravn Andersen

Antworten:

7

Ich denke, dass .sh.versiones das seit der ersten Version von ATT ksh 93 gibt. Es ist nicht in pdksh oder mksh verfügbar. Da ${.sh.version}es sich bei anderen Shells als ksh93 um einen Syntaxfehler handelt, schließen Sie den Test in eine Subshell ein und schützen Sie ihn dahinter 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 startete im public domain ksh clone (pdksh) und wurde erst 2008 mit ksh93t zur aktuellen Korn-Shell hinzugefügt.

Anstatt auf eine Versionsnummer zu testen, sollten Sie die spezifische Funktion testen, die Ihnen Kummer macht. Die meisten Funktionen können getestet werden, indem Sie ein Konstrukt in einer Subshell ausprobieren und prüfen, ob es einen Fehler auslöst.

Gilles 'SO - hör auf böse zu sein'
quelle
Ich sehe keinen Unterschied, wenn ich eine Subshell benutze. Es wird immer noch ${.sh.version}als Syntaxfehler behandelt , der nicht abgeglichen werden kann. Die Nachricht, die ich bekomme, ist bad substitution.
Sildoreth,
@sil Wenn Sie eine Subshell verwenden, müssen Sie den Fehler abfangen. Leiten Sie Fehler um /dev/nullund ignorieren Sie den Exit-Status.
Gilles 'SO - hör auf, böse zu sein',
Ich verstehe was du sagst. Was ich sage ist, dass der Fehler nicht umleitet. Es wird immer auf der Konsole gedruckt. Ich habe dies unter Solaris, AIX und HP-UX versucht. und ksh zeigt dieses Verhalten in allen von ihnen.
Sildoreth
@Sildoreth Ah. Ich habe nur unter Linux getestet, und ich habe keines dieser Betriebssysteme zum Testen. Funktioniert das eval '_sh_version=$(echo "${.sh.version}")' 2>/dev/nullbesser?
Gilles 'SO - hör auf böse zu sein',
Das ist ein bisschen besser. Es funktioniert einwandfrei in Solaris und HP-UX. Unter AIX funktioniert es über die Befehlszeile, schlägt aber merkwürdigerweise erneut fehl, wenn ich versuche, es in eine Shell-Funktion zu integrieren.
Sildoreth
6

KSH_VERSIONwurde ksh93vor Version 93t nicht implementiert . Es wird festgelegt sein , mksh, pdksh, lksh. Um die Version von zu überprüfen ksh, können wir folgende Schritte ausführen:

  • Überprüfen KSH_VERSIONzu erkennen mksh, pdksh,lksh
  • Wenn der erste Schritt fehlschlägt, probieren Sie eine andere Funktion aus als ksh93und ksh88/86( Lassen Sie sich von David Korn zeigen ).

In diesem Sinne werde ich gehen mit:

case "$KSH_VERSION" in
  (*MIRBSD*|*PD*|*LEGACY*) printf '%s\n' "$KSH_VERSION" ;;
  (*) [ -z "$ERRNO" ] && printf '%s\n' "${.sh.version}" || echo ksh88/86 ;;
esac
cuonglm
quelle
Warum wird bei dieser Überprüfung nicht geprüft, ob $KSH_VERSIONnicht leer ist? Auf meinem Ubuntu-Rechner wird "ksh93" gedruckt, KSH_VERSIONist aber eingestellt.
Sildoreth
Dies würde fehlschlagen, wenn zuvor ausgeführter Code (z. B. .kshrc) die Variable KSH_VERSION mit einem zufälligen Wert manipuliert.
Juli
@jlliagre: Nein, da es als Skript ausgeführt wurde, liest es nicht .kshrc.
2.
Wenn die ENVVariable gesetzt ist (und normalerweise auf gesetzt ist ~/.kshrc), liest das Skript die .kshrcDatei definitiv . Natürlich wäre es ziemlich seltsam, wenn ein Skript eine falsche KSH_VERSION setzen würde, aber dies ist dennoch möglich, genauso wie die explizite Ausführung eines Skripts mit einem anderen Interpreter als dem in der ersten Zeile angegebenen eine mögliche Situation ist.
Juli,
@jlliagre: Auch wenn Sie es ändern können, erhalten Sie Segfault, wenn Sie auf KSH_VERSION. verweisen . Und in mksh, pdksh, lksh, KSH_VERSIONwird als Nur - Lese markiert.
2.
5

Für "echte" kshReleases (dh AT & T-basiert) verwende ich diesen Befehl:

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

Hier sind verschiedene Ausgaben, die ich bekomme:

Original ksh:

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

dtksh;

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

Modernes ksh93:

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

Für pdksh/ msh kshclones und moderne AT & T- kshVersionen funktioniert Folgendes:

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

Bearbeiten:

Ich habe übersehen, dass Sie innerhalb eines Skripts gefragt haben, ob Sie dies tun möchten, ohne den Pfad zur getesteten ksh-Binärdatei zu kennen.

Angenommen, Sie möchten wirklich die verwendete Version kshund nicht die unterstützten Funktionen, dann können Sie dies auf eine Weise tun, indem Sie nur den stringsBefehl verwenden, der zumindest unter Linux und Solaris funktionieren sollte:

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)

Beachten Sie, dass diese Methode unzuverlässig ist, da sie /procmöglicherweise nicht bereitgestellt wird, und dass es sicherlich andere Schwachstellen gibt. Es ist auf anderen Unix-Betriebssystemen nicht getestet.

jlliagre
quelle
Dies wird nicht zwischen lkshund pdkshin Debian Jessie unterscheiden.
1.
@ Cuonglm Ich habe keine Jessie zu testen. Meinen Sie lkshund pdkshkönnen nicht von ihren aussortiert werden KSH_VERSION?
Juli,
Nein, ich meine stringsauf ihnen laufen . KSH_VERSIONdefinitiv können.
1.
@ Cuonglm Sorry, wenn ich unklar war. Als ich «für" echte " kshVeröffentlichungen» schrieb, schloss ich explizit Klone wie pdksh, mkshund aus , die nicht von AT & T stammen lksh.
Juli,
Das Ausführen stringsauf einer ksh-Binärdatei ist eine schlechte Idee, da Sie nicht wissen, ob dies diejenige ist, die Ihr Skript ausführt. Vielleicht wird Ihr Skript von /usr/local/bin/kshoder /home/bob/bin/kshoder /bin/shoder /usr/posix/bin/shoder ausgeführt ...
Gilles 'SO - hören Sie auf, böse zu sein'
2

Während ich ein Skript für schrieb ksh, bemerkte ich, dass die -aOption des integrierten whenceBefehls von ksh in älteren Versionen von anscheinend nicht unterstützt wird ksh. Dies scheint auf allen von mir überprüften Systemen zuzutreffen, darunter Solaris, AIX, HP-UX und Linux.

Also hier ist die Lösung als ksh-Funktion:

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
}

Und so benutzt man es:

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
Sildoreth
quelle
Warum benutzt du nicht ${.sh.version}?
6.
@ Cuonglm, weil ich nicht kann. Siehe die Kommentare zu Gilles 'Antwort .
Sildoreth,
Leider hat der whencein Zsh-a
Greg A. Woods
@ GregA.Woods, diese Funktion ist speziell für ksh. Die Funktionsdefinition würde in .kshrc abgelegt und würde daher nicht einmal für andere Shells wie zsh existieren. zsh hat einen eigenen eingebauten whenceBefehl, der in keiner Weise an ksh oder die Version davon gebunden ist. Ich weiß nicht einmal, warum Sie prüfen sollten, ob ksh eine alte Version aus einer Instanz von zsh ist, einer völlig anderen Shell.
Sildoreth
Es gibt ein Problem mit Ihren Annahmen: Zsh wird oft mit einem Link zu installiert /bin/ksh, zB unter Debian Linux. Jetzt benutze ich es dort nicht (und im Moment kann ich meine Login-Shell nicht ändern, um es zu überprüfen), also weiß ich nicht, ob es liest .kshrcoder nicht, aber ich würde vermuten, dass es das tut.
Greg A. Woods
1

CTRL+ ALT+V

oder

ESC, CTRL+V

Hat sich in der Regel als sehr zuverlässig erwiesen, wenn es darum geht, die von Ihnen verwendete KSH-Version interaktiv zu bestimmen. Die Skripterstellung hat sich jedoch als schwieriger erwiesen.

Tim Kennedy
quelle
1
Dies war die einzige, die für eine AIX ksh 88f-Version funktioniert hat.
Jeff Schaller
1
Ich habe die Option <kbd> ESC </ kbd>, <kbd> STRG </ kbd> + <kbd> V </ kbd> aktiviert, nachdem ich ausgeführt habe set -o vi, um die Tastenkombinationen auf vi-like einzustellen. Vorher oder mit + o vi oder -o emacs würde es mir einfach nicht zeigen. PD KSH v5.2.14 99/07 / 13.2 auf openbsd 6.1
bgStack15
0

Ich denke, das grundlegende Problem bei der Verwendung von $ {. Sh.version} ist, dass ksh88 mit einem Exit-Code ungleich Null einfach stoppt.

Meine Lösung besteht also darin, den Code, der auf $ {. Sh.version} verweist, in eine Sub-Shell einzufügen und dann zu testen, ob die Sub-Shell nicht null ist und Code in der Sub-Shell enthält, der für Versionen von funktioniert Das ksh, in dem der Verweis auf $ {. sh.version} funktioniert. Wrapping in eine Funktion, die dann von einer anderen Funktion aufgerufen wird, die den Rückkehrcode umkehrt, so dass der letzte Aufruf auf true überprüft.

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"

Ich habe dies unter AIX und Oracle Enterprise Linux 5 & 6 mit ksh88, ksh93 und pdksh ausgeführt.

Pete

Pete
quelle
1
moderne AT & T Ksh liefert noch .sh.version(in der Tat KSH_VERSIONist ein Pseudonym dafür). Auch einige Shells, z. B. NetBSD sh, hören nach dem Auffinden einfach auf zu lesen, ${.sh.version}und keine Umleitung kann dazu führen, dass sie das Skript ausführen.
Greg A. Woods
0

Das Folgende scheint für alle Shells, die ich getestet habe, einigermaßen zu funktionieren, einschließlich des alten ksh88e und einer fast vollständigen Reihe gängiger Ksh-Klone (obwohl nur eine Version von jeder), obwohl ich noch keine tatsächliche Original-Bourne-Shell getestet habe ( und dazu muss möglicherweise der testAusdruck für ältere Versionen angepasst werden ....

Nachtrag:

Ich habe dies jetzt auch erfolgreich mit Heirloom Bourne Shell getestet, allerdings mit einem externen (und moderneren) testProgramm.

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"
Greg A. Woods
quelle
Warum sollten Sie diese Funktion für Shells ausführen, die nicht ksh sind? Wenn Sie ein Skript in bash oder zsh ausführen, kommt ksh nie ins Spiel. Darüber hinaus wurde dies bereits durch die Antworten anderer festgestellt, ${.sh.version}die nicht Teil der Lösung sein können, da bestimmte Versionen von ksh - die Versionen, um die sich der ursprüngliche Beitrag gekümmert hat - in dieser Syntax fatalerweise fehlerhaft sind.
Sildoreth
Wie gesagt, die von mir gezeigte Funktion wurde mit Versionen von ksh getestet, die "fatale" Fehler verursachen, sowie mit Versionen von Ash, die dasselbe tun.
Greg A. Woods
Von mir geschriebene Skripte sollen portierbar sein und von jeder fähigen Shell ausgeführt werden. Wie ich bereits an anderer Stelle sagte, werden einige Leute nicht unbedingt wissen, dass sie Zsh als Ksh verwenden, da bei der Eingabe von 'ksh' die Zsh-Binärdatei aufgerufen wird (mit argv [0] als "ksh").
Greg A. Woods
Das gibt Aufschluss darüber, woher Sie kommen. Das klingt jedoch nach einer unrealistischen Anforderung. Wenn ein Unix-Entwickler "portabel" sagt, bedeutet dies in der Regel nicht "dieser Code wird in einer beliebigen Shell ausgeführt ", sondern "dies wird auf einem beliebigen System ausgeführt ". Und wenn Sie ein Skript ausführen müssen, das für eine andere Shell geschrieben wurde, ist das vollkommen legal. Starten Sie einfach eine nicht interaktive Instanz der anderen Shell in Ihrem Skript. Ich erwähne dies, weil ich gute Codierungspraktiken fördern möchte. Wenn diese Lösung für Sie funktioniert, großartig. Aber ich würde anderen raten, einen einfacheren Ansatz zu wählen.
Sildoreth
1
Zugegebenermaßen sind alle Bemühungen, die Abwärtskompatibilität zu weit in die Vergangenheit zu rücken, ziemlich dumm. Ich habe nur Versionen des alten AT & T Ksh und Unix Sh kompiliert, um meinen persönlichen Wunsch zu befriedigen, die Geschichte und die Entwicklung einiger Funktionen besser zu verstehen und meine Erinnerung an den Stand der Dinge aufzufrischen (was mich normalerweise überrascht, da die Dinge oft viel waren). besser ", als ich mich erinnere, obwohl sie manchmal auch viel schlimmer waren).
Greg A. Woods