
¿Hay alguna forma de crear un enlace que se actualice dinámicamente? Mi situación específica es que tengo varios ejercicios (directorios) y quiero vincularlos al último:
exercises/
│ exercise_01/
│ │ files ...
│ exercise_02/
│ │ files ...
│ exercise_03/
│ │ files ...
│ exercise_latest/ -> exercise_03/
entonces si cd exercises/exercise_latest
siempre va a la última. Agregar un nuevo directorio exercise_04
haría que el enlace apunte a ese.
Las soluciones que se me ocurren son:
- Un trabajo cron que se ejecuta una vez por minuto y se vuelve a vincular si detecta un nuevo directorio.
- No lo convierta en un enlace, sino en un script que
cd
vaya al directorio más reciente. - Manteniéndolo manualmente
Ninguna solución es particularmente elegante. 1.
Es realmente ineficiente y potencialmente demasiado lento. No puedo copiar archivos en 2.
. 3.
derrota el propósito.
Las versiones de software versionadas hacen algo similar. Por ejemplo, python3
siempre enlaza con la última versión de Python 3. Sin embargo, probablemente se actualicen cada vez que se instale una nueva versión.
¿Hay algo que pueda hacer que sea más elegante que mis ideas?
Respuesta1
La forma en que resolví esto es creando un agente launchctl/launchd que pueda escuchar archivos. Esto es específico de macOS, pero existen soluciones similares para 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>
Esto ejecuta un script de Python ( .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()
aquí LINK_ROOTS
contiene todos los archivos que se van a vincular. Todos los archivos que coincidan con una raíz de enlace con un guión bajo y cualquier número detrás coincidirán, el mayor se vinculará a la raíz del enlace.
Entonces, si LINK_ROOTS = ['exercise']
el más grande estará vinculado así exercise -> exercise_04
.
Esta no es una solución perfecta, pero funciona de manera bastante confiable y no es muy ineficiente.