シンボリックリンクとハードリンクは、1 つのファイルに複数の名前を付ける仕組みだ。Python ではどちらも作成・操作できる。
シンボリックリンクとハードリンクの違い
シンボリックリンク
ファイルの「パス」を指すショートカット。リンク先が削除されると壊れる(dangling link)。異なるファイルシステムを跨げる。ディレクトリにもリンクできる。
ハードリンク
同じ inode を共有する別名。どちらのリンクを削除しても、もう一方からアクセスできる。同じファイルシステム内でのみ作成可能。ディレクトリには作成できない。
シンボリックリンクを作成する
os.symlink() でシンボリックリンクを作成する。
import os
# target へのシンボリックリンクを link_name として作成
os.symlink('target.txt', 'link_to_target.txt')
pathlib でも同様に作成できる。
from pathlib import Path
Path('link_to_target.txt').symlink_to('target.txt')
ディレクトリへのシンボリックリンクを作成する場合は、target_is_directory=True を指定する(Windows で必要)。
os.symlink('mydir', 'link_to_dir', target_is_directory=True)
ハードリンクを作成する
os.link() でハードリンクを作成する。
import os
os.link('original.txt', 'hardlink.txt')
pathlib では link_to() を使う(Python 3.10 以降は hardlink_to())。
from pathlib import Path
# Python 3.10 以降
Path('hardlink.txt').hardlink_to('original.txt')
シンボリックリンクかどうかを判定する
import os
from pathlib import Path
# os.path
print(os.path.islink('link_to_target.txt')) # True
# pathlib
print(Path('link_to_target.txt').is_symlink()) # True
シンボリックリンクの参照先を取得する
import os
from pathlib import Path
# os
target = os.readlink('link_to_target.txt')
print(target) # target.txt
# pathlib
target = Path('link_to_target.txt').readlink()
print(target) # target.txt
シンボリックリンクを解決する
resolve() はシンボリックリンクをたどって最終的なパスを返す。
from pathlib import Path
# link -> dir/file.txt の場合
real_path = Path('link').resolve()
print(real_path) # /home/user/dir/file.txt
os.path.realpath() も同様だ。
import os
real_path = os.path.realpath('link')
リンクをたどらずに操作する
os.lstat() はシンボリックリンク自体の情報を返す(os.stat() はリンク先の情報を返す)。
import os
# リンク先の情報
stat_info = os.stat('link_to_target.txt')
# リンク自体の情報
lstat_info = os.lstat('link_to_target.txt')
ハードリンクの数を確認する
os.stat() の st_nlink でハードリンクの数がわかる。
import os
nlinks = os.stat('original.txt').st_nlink
print(f'リンク数: {nlinks}')
通常のファイルは 1、ハードリンクを作成すると 2 以上になる。
壊れたシンボリックリンクの検出
リンク先が存在しないシンボリックリンク(dangling link)を検出する。
from pathlib import Path
def is_broken_symlink(path):
p = Path(path)
return p.is_symlink() and not p.exists()
# 使用例
if is_broken_symlink('link_to_target.txt'):
print('壊れたシンボリックリンクです')
exists() はリンク先の存在を確認するが、is_symlink() はリンク自体の存在を確認する。両方を組み合わせることで壊れたリンクを検出できる。