Wie lässt sich ein Skript, das $0 verwendet, zum Laufen bringen, wenn es sich auf $PATH befindet?

Wie lässt sich ein Skript, das $0 verwendet, zum Laufen bringen, wenn es sich auf $PATH befindet?

Ich habe ein Skript (~/.../gremlin), für das ich einen Softlink erstellt habe:

ln -s ~/[...]/gremlin ~/sc/gremlin

~/sc/gremlinist in $PATH.
Der direkte Aufruf des Skripts funktioniert.
Der Aufruf über den Link funktioniert nicht.
Es verwendet dirname $0, sodass es nichts erhält.

Gibt es eine Möglichkeit, dieses Setup zum Laufen zu bringen, ohne das Skript zu ändern und ohne anstelle des Softlinks ein weiteres zu erstellen?

So wird $0 verwendet:

case `uname` in
  CYGWIN*)
    CP=$( echo `dirname $0`/../lib/*.jar . | sed 's/ /;/g')
    ;;
  *)
    CP=$( echo `dirname $0`/../lib/*.jar . | sed 's/ /:/g')
esac

Antwort1

Ob die Verwendung von dirname $0ein Problem darstellt oder nicht, hängt davon ab,Wiees wird verwendet. Ohne weitere Details können wir das nicht beantworten.

Wenn (a) die Verwendung dirname $0ein Problem darstellt und (b) Sie das Skript nicht ändern können, besteht die Lösung darin, den Softlink ~/sc/gremlindurch ein Skript zu ersetzen:

#!/bin/sh
exec ~/../gremlin "$@"

Auf diese Weise ~/../gremlinwird ein korrekter ausgeführt $0.

Die Verwendung von execbedeutet, dass der Prozess, der das Skript ausführt, ~/../gremlinden Prozess ersetzt, der ausgeführt wird ~/sc/gremlin. Dies ist effizienter, als beide Prozesse bis zum ~/../gremlinAbschluss beizubehalten.

Antwort2

~/...Wenn Sie das Verzeichnis nicht aus dem Skript heraus $0, sondern von ableiten möchten ~/sc, haben Sie folgende Möglichkeiten:

Wenn es ein zshSkript ist:

#! /bin/zsh -
dir=$0:A:h

Andernfalls und vorausgesetzt, Sie haben einen readlinkBefehl, der sich wie der von GNU verhält (einige Systeme haben einen realpathBefehl, den Sie möglicherweise stattdessen verwenden können):

#! /bin/sh -
dir=$(dirname -- "$(readlink -f -- "$0")")

readlink -fund $0:Agebe Ihnen diekanonischPfad der Datei, d. h. ein absoluter Pfad nach Auflösung aller symbolischen Links in allen Pfadkomponenten.

Und dann:

set -- "$dir"/../lib/*.jar .
case $(uname) in
  CYGWIN*) IFS=';';;
  *)       IFS=:;;
esac
CP="$*"

Oder:

case $(uname) in
  CYGWIN*) sep=';';;
  *)       sep=:;;
esac
CP=$(printf "%s$sep" "$dir"/../lib/*.jar).

Antwort3

Wie @john1024 anmerkte, könnte der Tippfehler in der Frage des OP der Kern der Frage sein:

ln -s ~/.../gremlin ~/sc/gremlin

Während einige Anwendungen dreifache Punkte akzeptieren, ist dies bei Unix-Dateisystemen nicht der Fall.Hülseerweitert die ~(Tilde), nicht ln, also

    ln -s ~/../gremlin ~/sc/gremlin

würde den Pfadnamen wie erwartet erweitern. Wenn der Link bereits existiert, können Sie ihn mit der -fOption überschreiben. Wenn das Ziel jedoch eine tatsächliche Datei ist, -füberschreibt die Option die Datei stillschweigend mit einem symbolischen Link. Vielleicht möchten Sie die -iOption verwenden, die Ihnen zumindest mitteilt, dass bereits etwas vorhanden ist.

Wenn Sie den Link validieren möchten (nachweisen möchten, dass er auf eine Datei verweist), ist die -Lfolgende Option lshilfreich:

ls -lL ~/sc/gremlin

Wenn es sich nicht um eine Datei handelt, lswird (je nach Implementierung) nur ein lfür den Typ (das erste Zeichen der Auflistung) mit Fragezeichen für die Berechtigungsbits oder ein anderer Hinweis angezeigt, der darauf hinweist, dass es sich nicht um eine echte Datei handelt (OSX weigert sich in diesem Fall einfach, überhaupt etwas anzuzeigen, obwohl es die Größe des symbolischen Links in die Gesamtsumme einbezieht).

Weiterführende Literatur:

verwandte Informationen