Есть ли способ, которым я могу создать ссылку, которая динамически обновляется. Моя конкретная ситуация заключается в том, что у меня есть несколько упражнений (каталогов), и я хочу сослаться на последнее:

exercises/
│   exercise_01/
│   │    files ...
│   exercise_02/
│   │    files ...
│   exercise_03/
│   │    files ...
│   exercise_latest/ -> exercise_03/

так что если я делаю cd exercises/exercise_latest он всегда идет к последнему. Добавление нового каталога exercise_04 сделало бы ссылку вместо этого.

Решения, которые я могу придумать:

  1. Задание cron, которое запускается раз в минуту и связывается заново, если обнаруживает новый каталог.
  2. Не сделать его ссылкой, а скрипт, который cd к последней директории.
  3. Вручную поддерживать его

Ни одно из решений не является особенно элегантным. 1. действительно неэффективно и потенциально слишком медленно. Я не могу скопировать файлы в 2. .. 3. побеждает цель.

Версии версий программного обеспечения делают нечто подобное. Например, python3 всегда ссылается на последнюю версию Python 3. Однако они, вероятно, обновляются каждый раз, когда устанавливается новая версия.

Могу ли я сделать что-нибудь более элегантное, чем мои идеи?

1 ответ1

0

Я решил это путем создания агента launchctl / launchd, который может прослушивать файлы. Это зависит от macOS, но для 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>

Это выполняет скрипт 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()

LINK_ROOTS здесь содержит все файлы, которые должны быть связаны. Все файлы, совпадающие с корнем ссылки с подчеркиванием и любыми числами позади, будут совпадать, самый большой из них будет связан с корнем ссылки.

поэтому, если LINK_ROOTS = ['exercise'] самое большое будет связано, как это exercise -> exercise_04 .

Это не идеальное решение, но оно работает достаточно надежно и не супер неэффективно.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .