`os.symlink` vs`ln -s`

时间:2013-03-22 21:50:04

标签: python linux bash symlink

我需要为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.walkglob.glob的解决方法是可行的,但我想知道是否可以使用os.symlink执行此操作。

3 个答案:

答案 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的事情。“

正确的答案是使用globfnmatchos.listdir加上正则表达式,或者您喜欢的任何内容。

使用os.walk,因为它会执行递归文件系统,因此它甚至不接近shell *扩展。

答案 1 :(得分:13)

*是一个shell扩展模式,在您的情况下指定“所有以/home/guest/dir1/开头的文件”。

但是 shell的角色是将此模式扩展到它匹配的文件。不是ln命令。

但是os.symlink不是shell,它是一个OS调用 - 因此,它不支持shell扩展模式。你必须在你的脚本中完成这项工作。

为此,您可以使用os.walkos.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)