Wie bearbeite ich den Pfad von Symlinks rekursiv?

Dies ist eine zusätzliche Frage, die mit dieser begann: Wie bearbeitet man symbolische Links in OS X?

Jetzt, da ich weiß, wie man den Pfad bearbeitet, auf den Symlinks verweisen, versuche ich herauszufinden, wie man das rekursiv für jeden defekten Symlink macht. Ich bin ein PHP-Typ, daher ist mir dieses CLI-Zeug etwas fremd ...

Es scheint einige spezifische Elemente dafür zu geben, nämlich:

  1. Identifizieren Sie einen defekten Symlink und rufen Sie seinen Standort ab
  2. Holen Sie sich das alte, jetzt falsche Ziel für den Symlink
  3. Konstruieren Sie den neuen korrekten Pfad, auf den der Symlink zeigen soll
  4. Bearbeiten Sie den Symlink

Das erste ist ziemlich einfach:

find /path/to/search -type l | while read f; do if [ ! -e "$f" ]; then ls -l "$f"; fi; done

Dadurch bekomme ich eine schöne Liste aller defekten Symlinks, die unterhalb des bereitgestellten Verzeichnisses gefunden wurden. Aber ich glaube, ich müsste die Position von jedem in einer Variablen (Array?) Speichern, um damit zu arbeiten.

Als nächstes scheint es, dass das Ändern der Aktion, die im "dann"-Teil der Logik bereitgestellt wird, die Lösung liefern würde.

Artikel 2 kann abgerufen werden mit:

readlink /path/to/broken/symlink

Es scheint also, dass wir das in eine Variable schieben müssen. Mir ist unklar, wie ich das im Terminal machen soll.

Nummer 3 wäre eine einfache Bearbeitung des in Schritt 2 abgerufenen Pfads. Ich muss den alten Laufwerksnamen durch den neuen ersetzen. Also ändern:

/Volumes/Old\ Drive/path/to/symlink

Zu

/Volumes/New\ Drive/path/to/symlink

Es ist auch unklar, wie genau dies in einem CLI-Skript zu tun ist. Eine Art Saitenersatz scheint erforderlich zu sein. So etwas wie str_replace in der PHP-Welt.

Schließlich kann Schritt 4 durchgeführt werden über:

ln -f -s /path/to/new/location/of/original /path/to/location/of/broken/symlink/

wie in meiner anderen Frage beschrieben, die zuvor oben verlinkt wurde.

Wie genau würde ich diese Konzepte aneinanderreihen, um das gewünschte Ergebnis zu erzielen, alle meine Symlinks auf einen Schlag zu reparieren?

Antworten (2)

Aus dem Kopf (und ohne jegliche Tests):

  1. Erstellen Sie eine Textdatei mit folgendem Inhalt

    #!/bin/bash
    
    find "$1" -type l | while read symlink; do
        if [ ! -e "$symlink" ]; then
            old_path=$(readlink "$symlink")
            new_path=${old_path/Old Drive/New Drive}
            ln -f -s "$new_path" "$symlink"
        fi
    done
    
  2. Machen Sie es ausführbar, indem Sie es ausführenchmod +x name-of-file

  3. Laufen./name-of-file /path/to/search

Dies ist ungetestet , also versuchen Sie es zuerst mit einem Beispielverzeichnis.


Um einige Erklärungen hinzuzufügen

  • old_path=$(readlink "$symlink")führt den Befehl aus $(...)und weist das Ergebnis zu$old_path
  • ${old_path/Old Drive/New Drive}macht Textersetzung an$old_path
Vielen Dank dafür, aber wenn ich versuche, das Skript wie angegeben auszuführen, bekomme ich einfachRun: Command not found
Nun, Sie müssen nur den Rest der Zeile eingeben (beginnend mit dem Punkt)
Ich habe von diesem eine neue bashSyntax gelernt. Also ein Upvote dafür! Danke!
Oh! Okay jetzt lief es. Scheint jedoch nichts zu tun ... die Symlinks haben einen neuen Zeitstempel, aber sie sind immer noch wie zuvor defekt. Beim Versuch, Ihren Code zu verstehen, ist mir nicht klar, wie er die Zeichenfolge für den alten Namen ersetzt, um ihn in den neuen zu ändern.
Es ist in der new_path=Zeile. Wenn Sie ein echtes Beispiel Ihres alten und neuen Pfads hinzufügen, kann ich das Skript entsprechend anpassen.
Ohhhh, das sollte ich ändern. Dachte irgendwie, es wäre dynamisch LOL. Ich werde es anpassen und zurückschreiben, wenn ich immer noch Probleme habe
Heiße Diggity, die perfekt funktioniert hat !! Vielen Dank für das einfache und elegante Skript!

Um in einer bashShell eine Variable zu setzen, verwenden Sie einfach set NAME=boboder set VITAL_SIGNS=none.

Sie können eine Variable auch mithilfe der Ausgabe eines Befehls festlegen, indem Sie die bashFunktion -builtin aufrufen read, um die Ausgabe einer benannten Variablen zuzuweisen. Dies funktioniert gut in einem Pipestream wie folgt:

ls -l | wc -l | read NUMBER_OF_LINES

Oder Sie können die Ausgabe direkt einer Variablen zuweisen:

LICENSE_KEY=$(cat ~/software/key.txt | grep KEY | awk '{print $1}')

Eine gute Möglichkeit, Variablen rekursiv zu lesen, ist in einer Schleife wie folgt:

for BROKEN_LINK in $(commands to produce a list of files)
do
commands here to sort your links out, noting that the broken links are stored in the variable $BROKEN_LINKS
done

In Anbetracht des oben Gesagten sollte so etwas wie das Folgende funktionieren:

beweisen, dass ein Ordner nicht existiert

StuffeMac:dan stuffe$ ls ~/Desktop/broken_links
ls: /Users/stuffe/Desktop/broken_links: No such file or directory

beweisen, dass ein neuer Zielordner existiert

StuffeMac:dan stuffe$ ls ~/Desktop/working_links
StuffeMac:dan stuffe$

Erstellen Sie einige ungültige und gültige Links

StuffeMac:dan stuffe$ ln -s ~/Desktop/brokenlinks/dan1
StuffeMac:dan stuffe$ ln -s ~/Desktop/brokenlinks/dan2
StuffeMac:dan stuffe$ ln -s ~/Desktop/working_links/dan3
StuffeMac:dan stuffe$ ln -s ~/Desktop/outofscopedeadlinks/dan4
StuffeMac:dan stuffe$ ls -l
total 32
lrwxr-xr-x  1 stuffe  staff  38  8 Dec 10:06 dan1 -> /Users/stuffe/Desktop/brokenlinks/dan1
lrwxr-xr-x  1 stuffe  staff  38  8 Dec 10:06 dan2 -> /Users/stuffe/Desktop/brokenlinks/dan2
lrwxr-xr-x  1 stuffe  staff  40  8 Dec 10:06 dan3 -> /Users/stuffe/Desktop/working_links/dan3
lrwxr-xr-x  1 stuffe  staff  46  8 Dec 10:21 dan4 -> /Users/stuffe/Desktop/outofscopedeadlinks/dan4

Holen Sie sich eine Liste toter Links in eine Datei zur Eingabe

StuffeMac:dan stuffe$ find . -type l | while read f; do if [ ! -e "$f" ]; then ls "$f" >> deadlinks.txt; fi; done
StuffeMac:dan stuffe$ more deadlinks.txt
./dan1
./dan2
./dan4

Führen Sie eine Schleife gegen jeden toten Link aus

StuffeMac:dan stuffe$ for DEAD_LINK in $(cat deadlinks.txt)
> do
> DESTINATION_IN_SCOPE=$(readlink $DEAD_LINK | grep brokenlinks | wc -l)
> NEW_DESTINATION="~/Desktop/working_links/"
> if [ $DESTINATION_IN_SCOPE = "1" ]
> then
> NEW_LINK=$(echo $DEAD_LINK | colrm 1 2)
> ln -f -s $NEW_DESTINATION$NEW_LINK $DEAD_LINK
> else
> echo "Link $DEAD_LINK not in target folder"
> fi
> done
Link ./dan4 not in target folder
StuffeMac:dan stuffe$

Überprüfen Sie die symbolischen Links nach den Änderungen

StuffeMac:dan stuffe$ ls -l
total 32
lrwxr-xr-x  1 stuffe  staff  28  8 Dec 10:08 dan1 -> ~/Desktop/working_links/dan1
lrwxr-xr-x  1 stuffe  staff  28  8 Dec 10:08 dan2 -> ~/Desktop/working_links/dan2
lrwxr-xr-x  1 stuffe  staff  40  8 Dec 10:06 dan3 -> /Users/stuffe/Desktop/working_links/dan3
lrwxr-xr-x  1 stuffe  staff  46  8 Dec 10:21 dan4 -> /Users/stuffe/Desktop/outofscopedeadlinks/dan4
Die modernere bashArt, die Ausgabe von Befehlen zu erfassen, besteht darin, die $(command)Syntax wie zu verwenden for MYVAR in $(ls | grep somefilter), anstatt Backticks zu verwenden. Es hat einige Vorteile gegenüber Backticks wie diesem . Ich habe auf dieser Grundlage Änderungen vorgenommen.
Es ist auch kein Witz, im SE-Markdown richtig zu parsen;)