
動的に更新されるリンクを作成する方法はありますか。私の具体的な状況としては、複数の演習 (ディレクトリ) があり、最新のものにリンクしたいというものです。
exercises/
│ exercise_01/
│ │ files ...
│ exercise_02/
│ │ files ...
│ exercise_03/
│ │ files ...
│ exercise_latest/ -> exercise_03/
つまり、cd exercises/exercise_latest
常に最新のものに移動します。新しいディレクトリを追加すると、exercise_04
リンクは代わりにそのディレクトリを指すようになります。
私が思いつく解決策は次のとおりです。
- 1 分間に 1 回実行され、新しいディレクトリを検出すると再リンクする cron ジョブ。
cd
リンクではなく、最新のディレクトリに移動するスクリプトにします。- 手動でメンテナンスする
どちらのソリューションも特にエレガントではありません。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
。
これは完璧な解決策ではありませんが、非常に信頼性が高く、非常に非効率的というわけではありません。