Wie kann ich herausfinden, ob ein relativer Symlink zu einem bestimmten Teilbaum gehört oder nicht?

7

Ich möchte testen, ob ein relativer Symlink auf den Teilbaum eines bestimmten Verzeichnisses verweist.

Dieses Beispiel würde ergeben, falseda es außerhalb des fooVerzeichnisses zeigt:
/foo>readlink bar
../fie.txt

Während dieses Beispiel ergeben würde true:
/foo>readlink bar
fum/fie.txt

Gibt es ein vorhandenes Dienstprogramm, das ich nutzen kann, oder muss ich es von Grund auf neu codieren? Ich benutze bash.

Fylke
quelle
Was ist, wenn fie.txtoder fumist es selbst ein Symlink außerhalb foo?
Stéphane Chazelas
Würden Sie dies immer ausführen /foooder müssen Sie in der Lage sein, beliebige Verzeichnisse zu übergeben? Ich meine, ist die Frage immer in Bezug auf ./oder nicht?
Terdon
@StephaneChazelas Ja, das ist ein Problem, das ich zumindest irgendwie ignoriere. Ich denke, ich werde den Link mit readlink -f erweitern und prüfen, ob die Präfixe übereinstimmen. Aber ich werde verrückte Eckfälle ignorieren, da sie in unserer Umgebung nicht existieren.
Fylke
@terdon Nein, es sollten beliebige Verzeichnisse akzeptiert werden.
Fylke
Schauen Sie sich Symlinks an , es kann helfen.
Monica wieder herstellen - M. Schröder

Antworten:

5

Ich glaube nicht, dass es so ein Dienstprogramm gibt. Mit GNU readlinkkönnen Sie Folgendes tun:

is_in() (
  needle=$(readlink -ve -- "$1" && echo .) || exit
  haystack=$(readlink -ve -- "$2" && echo .) || exit
  needle=${needle%??} haystack=${haystack%??}
  haystack=${haystack%/} needle=${needle%/}
  case $needle in
    ("$haystack" | "$haystack"/*) true;;
    (*) false;;
  esac
)

Dadurch werden alle Symlinks aufgelöst, sodass ein kanonischer absoluter Pfad für Nadel und Heuhaufen entsteht.

Erläuterung

  • Wir erhalten den kanonischen absoluten Pfad sowohl der Nadel als auch des Heuhaufens . Wir verwenden -estatt -f, um sicherzustellen, dass die Dateien vorhanden sind. Die -vOption gibt eine Fehlermeldung aus, wenn auf die Dateien nicht zugegriffen werden kann.
  • Wie immer --sollte verwendet werden, um das Ende von Optionen und Anführungszeichen zu markieren, da wir hier nicht den Operator split + glob aufrufen möchten.
  • Das Ersetzen von Befehlen in Bourne-ähnlichen Shells hat insofern eine Fehlfunktion, als das gesamte Zeilenumbruchzeichen am Ende der Ausgabe eines Befehls entfernt wird, nicht nur das, das durch Befehle zum Beenden der letzten Zeile hinzugefügt wurde. Was das bedeutet , ist , dass für eine Datei wie /foo<LF><LF>, $(readlink -ve -- "$1")zurückkehren würde /foo. Die übliche Problemumgehung besteht darin, ein Nicht-LF-Zeichen (hier .) anzuhängen und dieses und das zusätzliche LF-Zeichen, das mit hinzugefügt wurde, readlinkzu var=${var%??}entfernen (entfernen Sie die letzten beiden Zeichen).
  • Die Nadel gilt als im Heuhaufen, wenn es sich um den Heuhaufen handelt oder wenn es sich um einen Heuhaufen handelt. Das würde jedoch nicht funktionieren, wenn der Heuhaufen wäre /( /etcdenn stattdessen nicht //something). /muss oft speziell behandelt werden, denn während /und /xxmit der gleichen Anzahl von Schrägstrichen, ist einer eine Ebene über dem anderen.

    Eine Möglichkeit, dies zu beheben, besteht darin, es /durch die leere Zeichenfolge zu ersetzen, mit der fertig ist var=${var%/}(der einzige Pfad, der damit endet /, readlink -eist /, dass das Entfernen eines nachgestellten /Zeichens /in die leere Zeichenfolge geändert wird ).

Für die Kanonisierung der Dateipfade können Sie eine Hilfsfunktion verwenden.

canonicalize_path() {
  # canonicalize paths stored in supplied variables. `/` is returned as 
  # the empty string.
  for _var do
    eval '
      '"$_var"'=$(readlink -ve -- "${'"$_var"'}" && echo .) &&
      '"$_var"'=${'"$_var"'%??} &&
      '"$_var"'=${'"$_var"'%/}' || return
  done
}

is_in() (
  needle=$1 haystack=$2
  canonicalize_path needle haystack || exit
  case $needle in
    ("$haystack" | "$haystack"/*) true;;
    (*) false;;
  esac
)
Stéphane Chazelas
quelle
Ich fand das Studium dieses Beitrags sehr lehrreich. Darf ich Ihnen ein paar Fragen stellen? Hat es eine Bedeutung, dass in needle=${needle%??} haystack=${haystack%??}der needleVariablen zuerst behandelt wird, während es in der nächsten Zeile umgekehrt ist? Wie kommt es, dass Ihre returnAnweisungen nicht explizit einen Wert ungleich Null zurückgeben (um einen Fehler anzuzeigen)? Letzteres: Wäre es sinnvoll, die gesamte Transformation (den Aufruf von readlinkplus die beiden Suffix-Kürzungen) in eine separate _canonicalize_pathHilfsfunktion zu zerlegen?
Kjo
1
@kjo, 1) keine Bedeutung 2) returngibt standardmäßig den Status des letzten Befehls zurück. Mit || returnkönnen Sie den Status zurückgeben, der von der fehlgeschlagenen Anwendung bereitgestellt wird. 3) sicher, aber die resultierende Funktion wird wahrscheinlich kein angenehmer Anblick sein. Ich werde ein Beispiel hinzufügen.
Stéphane Chazelas
Vielen Dank! Ich verstehe was du meinst! Überhaupt kein angenehmer Anblick. Shell-Programmierung muss die schwierigste Art der Programmierung sein, die ich kenne ...
kjo
0

Ich habe das Problem folgendermaßen gelöst:

echo $abs_link_target | grep -qe "^$containing_dir"

Die $abs_link_targetVariable enthält den absoluten Pfad zum Symlink-Ziel (erweitert durch readlink -f). Ich überprüfe dann, ob der Anfang des Zielpfads mit dem Anfang des übereinstimmt$containing_dir

Fylke
quelle
Es würde sagen, dass / foobar in / foo ist
Stéphane Chazelas
Es würde sagen, dass / abc / d in / ab ist ( $containing_dirals regulärer Ausdruck genommen)
Stéphane Chazelas
Es würde sagen, dass / abc in ist /foo<LF>/abc(die Linien der Musterzeichenfolge werden als unterschiedliche Muster behandelt, um übereinzustimmen)
Stéphane Chazelas
Es würde heißen, dass /foo<LF>/abcin /abc( grepÜbereinstimmungen in jeder Zeile der Eingabe, nicht die gesamte Eingabe, daher kann im Allgemeinen nicht zum Abgleichen von Dateinamen verwendet werden).
Stéphane Chazelas
Abhängig von der echoImplementierung und / oder der Umgebung sollten Sie Probleme mit Dateinamen haben, die Backslashes enthalten. Sie echosollten wirklich nicht für den Umgang mit beliebigen Daten verwendet werden
Stéphane Chazelas,
0

grep -q "^/foo/bar/" <<< "$(readlink -f "anyfile.ext")"

fr00tyl00p
quelle
1
Unter der Annahme , das Ziel anyfile.extexistiert und ist erreichbar (ansonsten readlink -fim Gegensatz zu readlink -eMacht nicht geben Sie den richtigen Pfad) , und dass der resultierende Pfad Zeilenumbrüche enthält keine ( übernimmt zsh oder bash4 oder ksh93m + oder höher). Beachten Sie, dass wenn es anyfile.extauf sich /foo/barselbst zeigt, es sagt, dass es nicht innerhalb ist.
Stéphane Chazelas