944 Stimmen

Zuverlässiger Weg für ein Bash-Skript, den vollständigen Pfad zu sich selbst zu erhalten

Ich habe ein Bash-Skript, das seinen vollständigen Pfad kennen muss. Ich versuche, einen weitgehend kompatiblen Weg zu finden, um das zu tun, ohne mit relativen oder komisch aussehenden Pfaden zu enden. Ich brauche nur Bash zu unterstützen, nicht sh, csh, etc.

Was ich bis jetzt herausgefunden habe:

  1. Die akzeptierte Antwort auf Abrufen des Quellverzeichnisses eines Bash-Skripts aus Adressen, die den Pfad des Skripts über dirname $0 was in Ordnung ist, aber das kann zu einem relativ Pfad (wie . ), was ein Problem darstellt, wenn Sie Verzeichnisse im Skript ändern und der Pfad weiterhin auf das Skriptverzeichnis verweisen soll. Trotzdem, dirname wird ein Teil des Puzzles sein.

  2. Die akzeptierte Antwort auf Absoluter Pfad eines Bash-Skripts unter OS X (OS X-spezifisch, aber die Antwort funktioniert trotzdem) gibt eine Funktion an, die prüft, ob $0 relativ aussieht und, falls dies der Fall ist, vorangestellt wird $PWD dazu. Aber das Ergebnis kann immer noch relative Bits enthalten (obwohl es insgesamt absolut ist) - zum Beispiel, wenn das Skript t im Verzeichnis /usr/bin und Sie sind in /usr und Sie geben ein bin/../bin/t um es auszuführen (ja, das ist verworren), landet man bei /usr/bin/../bin als Verzeichnispfad für das Skript. Welche Werke ...aber...

  3. Le site readlink Lösung auf dieser Seite die wie folgt aussieht:

    # Absolute path to this script. /home/user/bin/foo.sh
    SCRIPT=$(readlink -f $0)
    # Absolute path this script is in. /home/user/bin
    SCRIPTPATH=`dirname $SCRIPT`

    Aber readlink ist nicht POSIX und die Lösung beruht offenbar auf GNUs readlink wo BSDs aus irgendeinem Grund nicht funktionieren (ich habe keinen Zugang zu einem BSD-ähnlichen System, um das zu überprüfen).

Es gibt also verschiedene Möglichkeiten, die aber alle ihre Tücken haben.

Was wäre ein besserer Weg? Wobei "besser" bedeutet:

  • Das gibt mir den absoluten Pfad.
  • Entfernt störende Teile, selbst wenn sie auf komplizierte Weise aufgerufen werden (siehe Kommentar zu Nr. 2 oben). (Z.B. wird der Pfad zumindest mäßig kanonisiert.)
  • Bezieht sich nur auf Bash-ismen oder Dinge, die mit ziemlicher Sicherheit in den meisten gängigen Varianten von *nix-Systemen (GNU/Linux, BSD und BSD-ähnlichen Systemen wie OS X usw.) enthalten sind.
  • Vermeidet, wenn möglich, den Aufruf externer Programme (z.B. bevorzugt Bash built-ins).
  • ( Aktualisiert danke für die Vorwarnung, welche ) Es muss keine Symlinks auflösen (mir wäre es sogar lieber, wenn es sie in Ruhe ließe, aber das ist keine Voraussetzung).

4voto

Abhijit Punkte 73

Einzeiler

`dirname $(realpath $0)`

3voto

VonC Punkte 1117238

Die akzeptierte Lösung hat den (für mich) unbequemen Nachteil, nicht "quellfähig" zu sein:
wenn Sie es von einem " source ../../yourScript ", $0 wäre " bash "!

Die folgende Funktion (für bash >= 3.0) liefert mir den richtigen Pfad, allerdings könnte das Skript (direkt oder über source (mit einem absoluten oder relativen Pfad):
(mit "richtigem Weg" meine ich den vollständiger absoluter Pfad des aufzurufenden Skripts auch wenn es von einem anderen Pfad aus direkt oder mit " source ")

#!/bin/bash
echo $0 executed

function bashscriptpath() {
  local _sp=$1
  local ascript="$0"
  local asp="$(dirname $0)"
  #echo "b1 asp '$asp', b1 ascript '$ascript'"
  if [[ "$asp" == "." && "$ascript" != "bash" && "$ascript" != "./.bashrc" ]] ; then asp="${BASH_SOURCE[0]%/*}"
  elif [[ "$asp" == "." && "$ascript" == "./.bashrc" ]] ; then asp=$(pwd)
  else
    if [[ "$ascript" == "bash" ]] ; then
      ascript=${BASH_SOURCE[0]}
      asp="$(dirname $ascript)"
    fi  
    #echo "b2 asp '$asp', b2 ascript '$ascript'"
    if [[ "${ascript#/}" != "$ascript" ]]; then asp=$asp ;
    elif [[ "${ascript#../}" != "$ascript" ]]; then
      asp=$(pwd)
      while [[ "${ascript#../}" != "$ascript" ]]; do
        asp=${asp%/*}
        ascript=${ascript#../}
      done
    elif [[ "${ascript#*/}" != "$ascript" ]];  then
      if [[ "$asp" == "." ]] ; then asp=$(pwd) ; else asp="$(pwd)/${asp}"; fi
    fi  
  fi  
  eval $_sp="'$asp'"
}

bashscriptpath H
export H=${H}

Der Schlüssel ist, die " source " zu verwenden und ${BASH_SOURCE[0]} um das eigentliche Skript zurückzubekommen.

2voto

wich Punkte 15933

Vielleicht ist die akzeptierte Antwort auf die folgende Frage hilfreich.

Wie kann ich das Verhalten von GNU's readlink -f auf einem Mac erhalten?

Da Sie nur den Namen kanonisieren wollen, den Sie durch die Verkettung von $PWD y $0 (unter der Annahme, dass $0 nicht von vornherein absolut ist), verwenden Sie einfach eine Reihe von Regex-Ersetzungen entlang der Linie von abs_dir=${abs_dir//\/.\//\/} und so weiter.

Ja, ich weiß, es sieht furchtbar aus, aber es wird funktionieren und ist Bash pur.

1voto

diyism Punkte 11786

Versuchen Sie dies:

cd $(dirname $([ -L $0 ] && readlink -f $0 || echo $0))

1voto

andro Punkte 11

Ich habe den folgenden Ansatz eine Zeit lang erfolgreich verwendet (allerdings nicht unter OS X), und er verwendet nur eine eingebaute Shell und behandelt den Fall "source foobar.sh", soweit ich das gesehen habe.

Ein Problem mit dem (hastig zusammengestellten) Beispielcode unten ist, dass die Funktion $PWD verwendet, das zum Zeitpunkt des Funktionsaufrufs korrekt sein kann oder auch nicht. Das muss also gehandhabt werden.

#!/bin/bash

function canonical_path() {
  # Handle relative vs absolute path
  [ ${1:0:1} == '/' ] && x=$1 || x=$PWD/$1
  # Change to dirname of x
  cd ${x%/*}
  # Combine new pwd with basename of x
  echo $(pwd -P)/${x##*/}
  cd $OLDPWD
}

echo $(canonical_path "${BASH_SOURCE[0]}")

type [
type cd
type echo
type pwd

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X