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
`os.symlink` vs `ln -s`
提问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.symlink
I 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 subprocess
and run ln
command. I don't want that solution.
我知道我可以使用subprocess
和运行ln
命令。我不想要那个解决方案。
I'm also aware that workarounds using os.walk
or glob.glob
are 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.symlink
creates a single symlink.
os.symlink
创建单个符号链接。
ln -s
creates 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 exec
the ln
command 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通过将通配符转换为多个参数来实现这一点。如果你是刚刚exec
的ln
命令使用通配符,它会寻找一个单一来源字面上命名*
中/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.symlink
alone—either part of it—because it doesn't do that. It's like saying "I want to do the equivalent of find . -name foo
using os.walk
without 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.listdir
plus 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 ln
command's.
但是您的shell 的职责是将此模式扩展到它匹配的文件。不是ln
命令的。
But os.symlink
is 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.walk
wouldn'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.listdir
is 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)