
Gibt es eine Möglichkeit, einen Link zu erstellen, der dynamisch aktualisiert wird? Meine spezielle Situation ist, dass ich mehrere Übungen (Verzeichnisse) habe und auf die neueste verlinken möchte:
exercises/
│ exercise_01/
│ │ files ...
│ exercise_02/
│ │ files ...
│ exercise_03/
│ │ files ...
│ exercise_latest/ -> exercise_03/
also wenn ich cd exercises/exercise_latest
es tue, wird immer das neueste angezeigt. Wenn ich ein neues Verzeichnis hinzufüge, exercise_04
wird der Link stattdessen auf dieses verweisen.
Die Lösungen, die mir einfallen, sind:
- Ein Cron-Job, der einmal pro Minute ausgeführt wird und eine neue Verknüpfung herstellt, wenn er ein neues Verzeichnis erkennt.
- Machen Sie daraus keinen Link, sondern ein Skript, das
cd
zum aktuellsten Verzeichnis führt. - Manuelle Wartung
Keine der Lösungen ist besonders elegant. 1.
ist wirklich ineffizient und möglicherweise zu langsam. Ich kann keine Dateien in kopieren 2.
. 3.
macht den Zweck zunichte.
Versionierte Software-Releases machen etwas Ähnliches. Sie verlinken beispielsweise python3
immer auf die neueste Python 3-Version. Sie werden jedoch wahrscheinlich jedes Mal aktualisiert, wenn eine neue Version installiert wird.
Kann ich etwas tun, das eleganter ist als meine Ideen?
Antwort1
Ich habe das Problem gelöst, indem ich einen launchctl / launchd-Agenten erstellt habe, der Dateien abhören kann. Dies ist macOS-spezifisch, aber es gibt ähnliche Lösungen für Linux.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC -//Apple Computer//DTD PLIST 1.0//EN
http://www.apple.com/DTDs/PropertyList-1.0.dtd>
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.me.exercise_listener.plist</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/python3</string>
<string>/path/to/exercises/.ln_monitor.py</string>
</array>
<key>WatchPaths</key>
<array>
<string>/path/to/exercises/</string>
</array>
<key>StandardOutPath</key>
<string>/path/to/exercises/.ln_monitor.log</string>
<key>StandardErrorPath</key>
<string>/path/to/exercises/.ln_monitor.log</string>
</dict>
</plist>
Dies führt ein Python-Skript aus ( .ln_monitor.py
)
#!/usr/bin/env python3
import os
import re
from pathlib import Path
import time
DIR = Path(os.path.dirname(os.path.realpath(__file__)))
LINK_ROOTS = ['exercise']
VERBOSE = True
def cprint(*args):
if VERBOSE:
print(*args)
def main():
for root in LINK_ROOTS:
regex = r'^' + root + r'_\d+$'
matches = [
directory for directory in DIR.iterdir()
if directory.is_dir() and
re.match(regex, directory.name)]
match_link = DIR / root
if matches:
match = sorted(matches)[-1]
cprint(f'link to {match.name}')
if match_link.is_symlink():
if match_link.resolve() == match:
cprint('is already linked')
continue
match_link.unlink()
cprint('unlinking')
time.sleep(0.5)
else:
cprint('no link yet')
match_link.symlink_to(match)
cprint('linked')
if __name__ == '__main__':
main()
Hier LINK_ROOTS
stehen alle Dateien, die verlinkt werden sollen. Alle Dateien, die zu einem Linkstamm mit Unterstrich und eventuell dahinter stehenden Zahlen passen, werden gematcht, die größte davon wird zum Linkstamm verlinkt.
also wenn LINK_ROOTS = ['exercise']
das Größte so verlinkt wird exercise -> exercise_04
.
Dies ist keine perfekte Lösung, aber sie funktioniert ziemlich zuverlässig und ist nicht übermäßig ineffizient.