Suchen Sie den Speicherort des Shell-Skripts

8

Ist es möglich, dass ein Shell-Skript seinen Speicherort kennt? Ich habe gelesen , um sourced Shell - Skript zu bestimmen Pfad aber die Antworten konzentrieren sich auf bashund tcshund fehlschlagen , wenn ein POSIX - Shell verwendet wird. $0ist auch nicht die Lösung und liefert falsche Ergebnisse .

Eine Lösung muss nicht 100% zuverlässig sein. Es ist unwahrscheinlich, dass der Pfad Hard- oder Symlinks enthält.

# sourcing the script should yield the absolute path to the script
. somedir/thescript

# within “thescript”
-> /tmp/foo/bar/somedir

Einige Hintergrundinformationen: Das Skript ist Teil einer vorhandenen Anwendung, die Dutzende von Binärdateien in einem binVerzeichnis an einem bekannten Speicherort enthält (variiert je nach Architektur), bezogen auf das Quellenskript. Um die Anwendung zu verwenden, bezieht der Benutzer das Skript, mit dem das binVerzeichnis vorangestellt wird PATH, sodass die Binärdateien der Anwendung problemlos in der aktuellen Shell (je nachdem, welche Shell sich befindet) aufgerufen werden können.

Marco
quelle
Bitte überprüfen Sie einmal diesen Link könnte das sein, wonach Sie suchen paste.ubuntu.com/6242655
Rahul Patil
@ RahulPatil Das funktioniert nur bei Bash und ist höchst unportabel.
Marco
1
Ich bin mir ziemlich sicher, dass die Antwort nein ist. Sie haben nur Shell-spezifische Methoden gefunden, da es keine portable Methode gibt. Wofür brauchst du das? Können Sie den Benutzern des Skripts anweisen, etwas anderes . /path/to/scriptals MARCO_DIR=/path/to; . $MARCO_DIR/scriptoder zu tun eval "$(/path/to/script)"? @ RahulPatil BASH_SOURCEist offensichtlich spezifisch für Bash.
Gilles 'SO - hör auf böse zu sein'
@ Gilles Wie gesagt, es muss nicht sehr robust sein. Aber ich habe keinen Weg gefunden, der in den einfachsten Fällen in einer POSIX-Shell auch nur aus der Ferne funktioniert. (Die Lösung für den Moment ist also, dass für die Verwendung dieser Anwendung eine der unterstützten Shells erforderlich ist.) Wenn dies die Antwort ist, können Sie "Nein ..." als Antwort eingeben.
Marco
@ Gilles Eine Änderung der Art und Weise, wie die Anwendung eingerichtet ist, ist keine Option. Es würde die Installationen brechen. Deshalb hätte ich das Skript gerne robuster gemacht, ohne die Art und Weise zu ändern, wie es heißt. Am Ende wird nur der PFAD festgelegt. Wenn das Skript fehlschlägt, besteht der Fallback darin, die Binärdateien zu finden und ihren Pfad zur Umgebung hinzuzufügen.
Marco

Antworten:

9

Der Speicherort des Skripts ist nur verfügbar, wenn Sie eine Shell verwenden, die Erweiterungen der POSIX-Spezifikation bietet. Sie können dies mit dem folgenden Snippet testen:

env -i PATH=/usr/bin:/bin sh -c '. ./included.sh' | grep included

wo included.shenthält

echo "$0"
set

In bash ist der Name des Skripts in $BASH_SOURCE. In zsh (im zsh-Kompatibilitätsmodus, nicht im sh- oder ksh-Kompatibilitätsmodus) ist es in $0(beachten Sie, dass in einer Funktion $0stattdessen der Funktionsname angegeben ist). In pdksh und dash ist es nicht verfügbar. In ksh93 zeigt diese Methode die Lösung nicht an, aber der vollständige Pfad zum enthaltenen Skript ist verfügbar als ${.sh.file}.

Wenn es gut genug ist, bash oder ksh93 oder zsh zu benötigen, können Sie dieses Snippet verwenden:

if [ -n "$BASH_SOURCE" ]; then
  this_script=$BASH_SOURCE
elif [ -n "$ZSH_VERSION" ]; then
  setopt function_argzero
  this_script=$0
elif eval '[[ -n ${.sh.file} ]]' 2>/dev/null; then
  eval 'this_script=${.sh.file}'
else
  echo 1>&2 "Unsupported shell. Please use bash, ksh93 or zsh."
  exit 2
fi

Sie können versuchen, den Speicherort des Skripts zu erraten, indem Sie sich ansehen, welche Dateien die Shell geöffnet hat. Experimentell scheint dies mit dash und pdksh zu funktionieren, aber nicht mit bash oder ksh93, die zumindest für ein kurzes Skript die Skriptdatei geschlossen haben, bis sie zur Ausführung kommen.

  open_file=$(lsof -F n -p $$ | sed -n '$s/^n//p')
  if [ -n "$open_file" ]; then
    # best guess: $open_file is this script
  fi

Das Skript ist möglicherweise nicht die Datei mit dem Deskriptor mit der höchsten Nummer, wenn das Skript in einem komplexen Skript enthalten ist, das mit Umleitungen gespielt hat. Möglicherweise möchten Sie die geöffneten Dateien durchlaufen. Dies funktioniert ohnehin nicht garantiert. Die einzige zuverlässige Möglichkeit, ein Sourcing-Skript zu finden, ist die Verwendung von bash, ksh93 oder zsh.


Wenn Sie die Benutzeroberfläche ändern können, lassen Sie Ihr Skript anstelle der Beschaffung Ihres Skripts ein Shell-Snippet ausdrucken, an das es evalim Aufrufer übergeben werden soll. Dies ist, was Skripte zum Festlegen von Umgebungsvariablen normalerweise tun. Damit kann Ihr Skript unabhängig von den Abweichungen der Shell und der Shell-Konfiguration des Aufrufers geschrieben werden.

#!/bin/sh
FOO_DIR=$(dirname -- "$0")
cat <<EOF
FOO_DIR='$(printf %s "$FOO_DIR" | sed "s/'/'\\''/g")'
PATH="\$PATH:$FOO_DIR/bin";
export FOO_DIR PATH
EOF

Im Anrufer: eval "`/path/to/setenv`"

Gilles 'SO - hör auf böse zu sein'
quelle
0

Wenn Sie Gilles Antwort hinzufügen, können Sie möglicherweise das Shell-Skript ( if $0 = ash) über die /proc/$$ interface. Ich weiß nicht, wie genau das ist, aber es /proc/$$/fd/11scheint immer auf dieses Skript mit BusyBox 'Asche zu verweisen.

Bereitstellung als mögliche Antwort für diejenigen, die auf diese Seite stoßen (wie ich).

Die letzte Antwort wurde gelöscht - daher wird mein Anspruch auf diese Arbeit auf 4 verschiedenen HW-Plattformen (x86, ARM, XLP und PowerPC) getestet. Alle geben die gleiche Antwort von fd / 11. Ein Readlink von /proc/$$/fd/11liefert mein Skript.

Andy

A. Kennedy
quelle