動態連結目錄

動態連結目錄

有什麼方法可以建立動態更新的連結。我的具體情況是,我有多個練習(目錄),我想連結到最新的一個:

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

我解決這個問題的方法是建立一個可以監聽檔案的 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

這不是一個完美的解決方案,但它工作得相當可靠,而且效率也不是超級低。

相關內容