我需要为dir2中的dir1(文件或目录)的每个项创建一个符号链接。 dir2已经存在且不是符号链接。在Bash中,我可以通过以下方式轻松实现:
ln -s /home/guest/dir1/* /home/guest/dir2/
但是在python中使用os.symlink我收到一个错误:
>>> os.symlink('/home/guest/dir1/*', '/home/guest/dir2/')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OSError: [Errno 17] File exist
我知道我可以使用subprocess
并运行ln
命令。我不想要那个解决方案。
我也知道使用os.walk
或glob.glob
的解决方法是可行的,但我想知道是否可以使用os.symlink
执行此操作。
答案 0 :(得分:54)
os.symlink
创建一个符号链接。
ln -s
创建多个符号链接(如果它的最后一个参数是一个目录,并且有多个源)。 Python的等价物如下:
dst = args[-1]
for src in args[:-1]:
os.symlink(src, os.path.join(dst, os.path.dirname(src)))
那么,当你ln -s /home/guest/dir1/* /home/guest/dir2/
时它是如何工作的?您的 shell 通过将通配符转换为多个参数来实现这一点。如果你只是exec
带有通配符的ln
命令,它会在*
中找到一个名为/home/guest/dir1/
的单个源,而不是该目录中的所有文件。< / p>
Python等价物是这样的(如果你不介意将两个级别混合在一起并忽略很多其他情况 - 在shell上可能的波形符,env变量,命令替换等):
dst = args[-1]
for srcglob in args[:-1]:
for src in glob.glob(srcglob):
os.symlink(src, os.path.join(dst, os.path.dirname(src)))
你不能单独使用os.symlink
- 或者它的一部分 - 因为它没有这样做。这就像说“我希望使用find . -name foo
使用os.walk
而不过滤名称。”或者,就此而言,我想为我做相当于ln -s /home/guest/dir1/* /home/guest/dir2/
没有shell globbing的事情。“
正确的答案是使用glob
,fnmatch
,os.listdir
加上正则表达式,或者您喜欢的任何内容。
不使用os.walk
,因为它会执行递归文件系统,因此它甚至不接近shell *
扩展。
答案 1 :(得分:13)
*
是一个shell扩展模式,在您的情况下指定“所有以/home/guest/dir1/
开头的文件”。
但是 shell的角色是将此模式扩展到它匹配的文件。不是ln
命令。
但是os.symlink
不是shell,它是一个OS调用 - 因此,它不支持shell扩展模式。你必须在你的脚本中完成这项工作。
为此,您可以使用os.walk
或os.listdir
。如其他答案所示,适当的呼叫将取决于您想要做什么。 (os.walk
不等同于*
)
说服自己:在终端的Unix机器上运行此命令:python -c "import sys; print sys.argv" *
。你会看到它正在进行匹配的shell。
答案 2 :(得分:4)
根据@abarnert的建议,它是识别*
并将其替换为dir1内的所有项目的shell。因此,我认为使用os.listdir
是最佳选择:
for item in os.listdir('/home/guest/dir1'):
os.symlink('/home/guest/dir1/' + item, '/home/guest/dir2/' + item)