如何在Python中将符号链接更改为从一个文件指向另一个文件?
os.symlink
函数似乎只能用于创建新的符号链接。
如果您需要原子修改,则取消链接将不起作用。
更好的解决方案是创建一个新的临时符号链接,然后将其重命名为现有符号链接:
os.symlink(target, tmpLink)
os.rename(tmpLink, linkName)
您可以检查以确保它也已正确更新:
if os.path.realpath(linkName) == target:
# Symlink was updated
根据os.rename的文档,可能无法在Windows中自动更改符号链接。在这种情况下,您只需删除并重新创建。
Python2的一个小功能,尝试符号链接,如果由于现有文件而失败,它会删除它并再次链接。检查Tom Hale's answer以获取最新的解决方案。
import os, errno
def symlink_force(target, link_name):
try:
os.symlink(target, link_name)
except OSError, e:
if e.errno == errno.EEXIST:
os.remove(link_name)
os.symlink(target, link_name)
else:
raise e
您可以首先使用os.unlink()
,然后使用os.symlink()
重新创建指向新目标。
我最近研究了这个问题,并发现最好的方法确实是unlink
然后symlink
。但是,如果您只需要修复损坏的链接,例如使用自动替换,那么您可以执行os.readlink
:
for f in os.listdir(dir):
path = os.path.join(dir, f)
old_link = os.readlink(path)
new_link = old_link.replace(before, after)
os.unlink(path)
os.symlink(new_link, path)
给定overwrite=True
,此函数将使用符号链接安全地覆盖现有文件。
它认识到种族条件,这就是为什么它不短,但它是安全的。
import os, tempfile
def symlink(target, link_name, overwrite=False):
'''
Create a symbolic link named link_name pointing to target.
If link_name exists then FileExistsError is raised, unless overwrite=True.
When trying to overwrite a directory, IsADirectoryError is raised.
'''
if not overwrite:
os.symlink(target, linkname)
return
# os.replace() may fail if files are on different filesystems
link_dir = os.path.dirname(link_name)
# Create link to target with temporary filename
while True:
temp_link_name = tempfile.mktemp(dir=link_dir)
# os.* functions mimic as closely as possible system functions
# The POSIX symlink() returns EEXIST if link_name already exists
# https://pubs.opengroup.org/onlinepubs/9699919799/functions/symlink.html
try:
os.symlink(target, temp_link_name)
break
except FileExistsError:
pass
# Replace link_name with temp_link_name
try:
# Pre-empt os.replace on a directory with a nicer message
if os.path.isdir(link_name):
raise IsADirectoryError(f"Cannot symlink over existing directory: '{link_name}'")
os.replace(temp_link_name, link_name)
except:
if os.path.islink(temp_link_name):
os.remove(temp_link_name)
raise
学生笔记:
temp_link_name
之前,在随机命名的link_name
上创建的符号链接可以被另一个进程修改。我提出了一个python issue,以突出os.symlink()
问题,要求目标不存在,我被建议提高my suggestion on the python-ideas
mailing list
在e.errno!= errno.EEXIST的情况下,不要忘记添加raise命令。您不想隐藏错误:
if e.errno == errno.EEXIST:
os.remove(link_name)
os.symlink(target, link_name)
else:
raise
一个快速简便的解决方案:
while True:
try:
os.symlink(target, link_name)
break
except FileExistsError:
os.remove(link_name)
但是,当替换应该始终存在的符号链接时,这会有竞争条件,例如:
/lib/critical.so -> /lib/critical.so.1.2
升级时:
my_symlink('/lib/critical.so.2.0', '/lib/critical.so')
有一个时间点/lib/critical.so
不存在。
This answer避免了竞争条件。