Linux `os.symlink` 与 `ln -s`

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15580425/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 22:32:04  来源:igfitidea点击:

`os.symlink` vs `ln -s`

pythonlinuxbashsymlink

提问by jurgenreza

I need to create a symlink for every item of dir1 (file or directory) inside dir2. dir2 already exists and is not a symlink. In Bash I can easily achieve this by:

我需要为 dir2 中的 dir1(文件或目录)的每个项目创建一个符号链接。dir2 已经存在并且不是符号链接。在 Bash 中,我可以通过以下方式轻松实现:

ln -s /home/guest/dir1/* /home/guest/dir2/

ln -s /home/guest/dir1/* /home/guest/dir2/

But in python using os.symlinkI get an error:

但是在 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

I know I can use subprocessand run lncommand. I don't want that solution.

我知道我可以使用subprocess和运行ln命令。我不想要那个解决方案。

I'm also aware that workarounds using os.walkor glob.globare possible, but I want to know if it is possible to do this using os.symlink.

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

采纳答案by abarnert

os.symlinkcreates a single symlink.

os.symlink创建单个符号链接。

ln -screates multiple symlinks (if its last argument is a directory, and there's more than one source). The Python equivalent is something like:

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

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

So, how does it work when you do ln -s /home/guest/dir1/* /home/guest/dir2/? Your shellmakes that work, by turning the wildcard into multiple arguments. If you were to just execthe lncommand with a wildcard, it would look for a single source literally named *in /home/guest/dir1/, not all files in that directory.

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

The Python equivalent is something like (if you don't mind mixing two levels together and ignoring a lot of other cases—tildes, env variables, command substitution, etc. that are possible at the shell):

Python 等价物类似于(如果您不介意将两个级别混合在一起并忽略许多其他情况 - 波浪号、环境变量、命令替换等,这些在 shell 中是可能的):

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)))

You can't do that with os.symlinkalone—either part of it—because it doesn't do that. It's like saying "I want to do the equivalent of find . -name foousing os.walkwithout filtering on the name." Or, for that matter, I want to do the equivalent of ln -s /home/guest/dir1/* /home/guest/dir2/without the shell globbing for me."

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

The right answer is to use glob, or fnmatch, or os.listdirplus a regex, or whatever you prefer.

正确的答案是使用glob, or fnmatch, oros.listdir加上正则表达式,或者你喜欢的任何东西。

Do notuse os.walk, because that does a recursivefilesystem walk, so it's not even close to shell *expansion.

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

回答by Thomas Orozco

*is a shell extension pattern, which in your case designates "all files starting with /home/guest/dir1/".

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

But it's your shell's role to expand this patternto the files it matches. Not the lncommand's.

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

But os.symlinkis not a shell, it's an OS call - hence, it doesn't support shell extension patterns. You'll have to do that work in your script.

os.symlink它不是外壳,而是操作系统调用 - 因此,它不支持外壳扩展模式。您必须在脚本中完成这项工作。

To do so, you can use os.walk, or os.listdir. As indicated in the other answer, the appropriate call will depend on what you want to do. (os.walkwouldn't be the equivalent of *)

为此,您可以使用os.walk, 或os.listdir。如另一个答案所示,适当的调用将取决于您想要做什么。(os.walk不会等同于*



To convince yourself: run this command on an Unix machine in your terminal: python -c "import sys; print sys.argv" *. You'll see that it's the shell that's doing the matching.

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

回答by jurgenreza

As suggested by @abarnert it's the shell that recognizes *and replaces it with all the items insside dir1. Therefore I think using os.listdiris the best choice:

正如@abernert 所建议的那样,它是外壳识别*并替换为 dir1 中的所有项目。因此我认为使用os.listdir是最好的选择:

for item in os.listdir('/home/guest/dir1'):
    os.symlink('/home/guest/dir1/' + item, '/home/guest/dir2/' + item)