`os.symlink` vs`ln -s`

jur*_*eza 38 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
Run Code Online (Sandbox Code Playgroud)

我知道我可以使用os.symlink并运行subprocess命令.我不想要那个解决方案.

我也知道使用lnos.walk可能的解决方法,但我想知道是否可以使用glob.glob.

aba*_*ert 62

os.symlink 创建一个符号链接.

ln -s创建多个符号链接(如果它的最后一个参数是一个目录,并且有多个源).Python的等价物是这样的:

dst = args[-1]
for src in args[:-1]:
    os.symlink(src, os.path.join(dst, os.path.dirname(src)))
Run Code Online (Sandbox Code Playgroud)

那么,当你这样做时它是如何工作的ln -s /home/guest/dir1/* /home/guest/dir2/?通过将通配符转换为多个参数,您的shell可以实现这一点.如果你是刚刚execln命令使用通配符,它会寻找一个单一来源字面上命名*/home/guest/dir1/,在该目录中没有的所有文件.

Python的等价物是这样的(如果你不介意将两个级别混合在一起并忽略很多其他情况 - 可能在shell上使用的tildes,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)))
Run Code Online (Sandbox Code Playgroud)

你不能os.symlink单独使用它 - 或者它的一部分 - 因为它没有那样做.这就像是说"我想在没有过滤名称的情况下做相当于find . -name foo使用的事情os.walk." 或者,就此而言,我想为我做相当于ln -s /home/guest/dir1/* /home/guest/dir2/没有shell globbing的事情."

正确的答案是使用glob,或者fnmatch,或者os.listdir加上一个正则表达式,或任何你喜欢的.

千万不能使用os.walk,因为做了递归文件系统的步行路程,所以它甚至还没有接近外壳*扩展.


Tho*_*zco 14

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

但是将shell模式扩展到它匹配的文件是你的shell的作用.不是ln命令的.

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

为此,您可以使用os.walk,或os.listdir.如其他答案所示,适当的呼叫将取决于您想要做什么.(os.walk不会相当于*)


说服自己:在终端的Unix机器上运行此命令:python -c "import sys; print sys.argv" *.你会看到它正在进行匹配的shell.


jur*_*eza 5

正如@abarnert所建议的那样,是外壳程序*将其识别并替换为dir1内的所有项目。因此,我认为使用os.listdir是最佳选择:

for item in os.listdir('/home/guest/dir1'):
    os.symlink('/home/guest/dir1/' + item, '/home/guest/dir2/' + item)
Run Code Online (Sandbox Code Playgroud)

  • 我建议使用`os.path.join`而不是`+`。 (5认同)