'switch' basierend auf Shell

7

Ich würde gerne Quelle (dh nicht nennen ) ein Skript von jedem Shell (bash / csh sind die primären Ziele, aber Fisch, zsh, KSH, und rc wäre auch interessant).

Ich möchte, ob das Skript eine einzelne Datei sein kann - dh nicht eine Datei für jeden Shell-Dialekt.

Kann ich das machen?

Ich denke an etwas Ähnliches wie:

  if shell is bash then
    # bash code here
  else
    if shell is csh then
      # csh code here
    else
      if shell is xxxsh then
        # xxxsh code here
      fi
    endif
  fi

Also kann ich tun:

csh% source my_script
bash$ . my_script

Das Problem ist - natürlich ifist das nicht in jedem Dialekt gleich, also muss ich irgendwie eine Syntax verwenden, die für jede Shell gültig ist.

Bearbeiten

Das Erkennen der Shell ist der erste Schritt, bei dem das Bestimmen der Shell im Skript zur Laufzeit hervorragende Arbeit leistet.

Ein ebenso wichtiger Schritt ist, wie der Code für die verschiedenen Abschnitte für Shells zitiert werden sollte, um andere Shells nicht zu verwirren. Denken Sie: Wie können Sie im Abschnitt für Bash <<here_documentalle Zeichen in allen Kombinationen enthalten, die in Bash legal, aber in jeder anderen Shell illegal sind, ohne dass dies die anderen Shells verwirrt? Dies wird von keiner der Antworten / verknüpften Antworten abgedeckt.

Ole Tange
quelle
1
Diese Art von Dingen ist möglich, erfordert jedoch normalerweise sehr spezifische Problemumgehungen und extreme Klugheit. Ich glaube nicht, dass es wirklich einen generischen und erweiterbaren Weg gibt, dies zu tun.
Tom Hunt
4
Hier ist ein Beispiel für extreme Klugheit von einem unserer eigenen: unix.stackexchange.com/a/71137/117549
Jeff Schaller
1
@ Scott Ich denke nicht, dass dies ein Duplikat ist. Das OP möchte hier in der Lage sein, einen anderen Befehlssatz basierend auf der verwendeten Shell auszuführen. Das Erkennen der Hülle ist zwar Teil der Lösung, reicht jedoch nicht aus. Wie können Sie, sobald Sie es erkannt haben, eine Sache für eine Shell und eine andere für eine andere Shell tun, ohne die Dinge in verschiedene Dateien aufzuteilen?
Terdon
2
Selbst wenn dies möglich ist, möchten Sie dies wirklich nicht tun. Anstatt die Seltsamkeiten einer einzigen Muschel zu erleiden, fügen Sie sich selbst die schrecklichen Macken vieler Muscheln zu.
Cas

Antworten:

2

Anstatt Codefragmente für jede Shell zu schreiben, sollten Sie nur tragbaren Code schreiben, der von den meisten Shells interpretiert werden kann. Sie sollten sich die POSIX Shell-Befehlssprache ansehen . Dies ist ein Standard, wie eine Shell (die POSIX berücksichtigt) Code interpretieren sollte.

Viele Shells bashkönnen so konfiguriert werden, dass sie sich wie eine POSIX-Shell verhalten. Jede Shell hat seine gewonnenen Eigenschaften und spezifischen Notationen. Vermeiden Sie sie vollständig in tragbaren Skripten.

Chaos
quelle
3
Das speziell erwähnte OP, cshdas neben seinen vielen anderen Fehlern mit Sicherheit nicht POSIX-konform ist, wird ihnen wahrscheinlich nicht viel helfen.
Terdon
1
csh - Skripten jemand Schreiben sollte nicht auf und bezeichnet beraten werden perl.com/doc/FMTEYEWTK/versus/csh.whynot und shlomifish.org/open-source/anti/csh Weg zurück in den dunklen Zeiten der 1980er Jahre, csh machte ein ziemlich anständige interaktive Shell, weil sie nette Funktionen wie das Abrufen und Bearbeiten des Verlaufs hatte. Andere, bessere Muscheln haben diese Eigenschaften längst ohne die Nachteile von csh gewonnen und übertroffen.
Cas
2

Für csh-like versus Bourne-like können Sie Folgendes tun:

start=:#||:<<"goto end="

echo "(t)csh code here"
if { bindkey >& /dev/null } then
  echo tcsh
endif

goto end=

echo Bourne-like code here
if [ -n "$BASH_VERSION" ]; then
  echo bash
fi

end=:

Erklärt:

  • start=:würde als Label-Deklaration in cshund Variablenzuweisung in behandelt werden sh, also zwei harmlose Operationen.
  • In start=:#, die #als Kommentar Führer behandelt wird csh, aber nicht in , shda es kein separates Token ist. Also, was danach ist, ist auskommentiert, cshaber nicht für sh.
  • Eine Variablenzuweisung shhat einen erfolgreichen Exit-Status (solange die Zuweisungen keine Befehlsersetzungen beinhalten), sodass das Befehlsrecht des ||Operators nicht ausgeführt wird.
  • Dieser :<<"goto end="...goto endBefehl wird nicht ausgeführt, sondern analysiert und ignoriert (die angegebene "goto end"Anführungszeichen verhindern verschiedene Erweiterungen im Dokument hier). Ein Hinweis jedoch: In der Bourne-Shell (und nur in der Bourne-Shell) wird noch eine temporäre Datei erstellt.
  • Also wird der gesamte Abschnitt bis goto end=von der Bourne-ähnlichen Shell ignoriert und von ausgeführt csh. goto end=bewirkt csh, dass der Teil zwischen diesem und end=:(eine harmlose Variablenzuweisung in Bourne-ähnlichen Shells) ignoriert wird .

Je mehr Shell-Unterstützung Sie hinzufügen, desto schwieriger wird es. Für fishbesonders, ist es ziemlich schwierig , da es die Syntax des gesamten Skript Ereignis prüft die Teile es nicht ausgeführt.

Siehe auch:

Stéphane Chazelas
quelle
-1

Ich gehe davon aus, dass der Grund, warum Sie dies tun möchten, die Portabilität ist. Die obigen Antworten geben Ihnen einen Hinweis. Wenn Sie davon ausgehen, dass die Bourne-Shell (sh) der kleinste gemeinsame Nenner ist und "überall" verfügbar ist (Linux, Solaris, Unix, AIX usw.), können Sie #!/bin/sham Anfang Ihres Skripts ein setzen und Ihr gesamtes Skript schreiben mit nur den Funktionen von sh. (Ich denke, dass sh unter Linux nur ein Alias ​​für bash ist, da bash eine Obermenge der Bourne-Shell ist, aber egal, es sollte trotzdem funktionieren.)

Eine leichte Verfeinerung ist anzunehmen, dass dies shimmer vorhanden ist, aber Sie benötigen möglicherweise die zusätzliche Kraft und Bequemlichkeit einiger der fortschrittlicheren Muscheln. Sie können also eine Version des Skripts für jede der von Ihnen unterstützten Shells schreiben, z. B. script.bash, script.zsh, script.ksh, script.csh usw., wobei jede mit einer eigenen Shebang-Zeile beginnt und dann im Skript. sh Datei würden Sie etwas sagen wie:

#!/bin/sh
if [[ -e /bin/ksh ]] ; then 
 ./script.ksh
 exit
elif [[ -e /bin/csh ]] ; then
 ./script.csh
 exit
fi

usw.

Ein weiterer Vorschlag ist, den Quellcode der Auto-Tools-Toolkette zu untersuchen. Die Dinge, die ausgeführt werden, wenn Sie eine ./configure; machen ; make install. Die GNU-Leute haben viele clevere Dinge getan, um sicherzustellen, dass ihre Skripte in allen Umgebungen ausgeführt werden.

pgmer6809
quelle
Das OP erwähnte ausdrücklich , dass es vermeiden möchte, ein separates Skript pro Shell zu haben. Außerdem prüft Ihre Lösung, ob die Shells auf dem System vorhanden sind, und nicht, welcher Interpreter das Skript gerade liest. Dies hilft also auch nicht weiter. Beachten Sie schließlich, dass es sich heutzutage shhäufig um einen Link zu handelt dash, aber selbst wenn es sich tatsächlich um einen Link zu handelt bash, führt das Aufrufen bashals dazu, shdass es im POSIX-Modus ausgeführt wird und sich eher wie herkömmlich verhält shals bash.
Terdon