Kod*_*rok 156 python linux operating-system
我试图了解使用Python的库函数执行特定于操作系统的任务(例如创建文件/目录,更改文件属性等)而不仅仅通过os.system()
或执行这些命令的动机是什么subprocess.call()
?
例如,为什么我要使用os.chmod
而不是做os.system("chmod...")
?
我知道尽可能多地使用Python的可用库方法而不是直接执行shell命令更"pythonic".但是,从功能的角度来看,还有其他动机吗?
我只是在谈论在这里执行简单的单行shell命令.当我们需要更多地控制任务的执行时,我理解使用subprocess
模块更有意义,例如.
Fli*_*imm 325
它更快,os.system
并subprocess.call
创建新的流程,这对于这么简单的事情是不必要的.实际上,os.system
并且subprocess.call
通过shell
参数通常会创建至少两个新进程:第一个是shell,第二个是您正在运行的命令(如果它不是内置的shell test
).
某些命令在单独的进程中无用.例如,如果运行os.spawn("cd dir/")
,它将更改子进程的当前工作目录,但不会更改Python进程的当前工作目录.你需要使用os.chdir
它.
您不必担心shell 解释的特殊字符.os.chmod(path, mode)
无论文件名是什么都可以工作,但os.spawn("chmod 777 " + path)
如果文件名是这样的话会失败; rm -rf ~
.(请注意,您可以解决这个,如果你使用subprocess.call
不带shell
参数).
您不必担心以破折号开头的文件名.os.chmod("--quiet", mode)
将更改命名文件的权限--quiet
,但os.spawn("chmod 777 --quiet")
将失败,因为它--quiet
被解释为参数.即便如此也是如此subprocess.call(["chmod", "777", "--quiet"])
.
您的跨平台和跨shell问题较少,因为Python的标准库应该为您处理.你的系统有chmod
命令吗?它安装了吗?它是否支持您希望它支持的参数?该os
模块将尝试尽可能跨平台,并在不可能时提供文档.
如果您正在运行的命令具有您关心的输出,则需要解析它,这比听起来更棘手,因为您可能会忘记角落情况(文件名中包含空格,制表符和换行符),即使您不关心可移植性.
iPr*_*ram 133
它更安全.这里给出一个想法是一个示例脚本
import os
file = raw_input("Please enter a file: ")
os.system("chmod 777 " + file)
Run Code Online (Sandbox Code Playgroud)
如果来自用户的输入是test; rm -rf ~
,那么将删除主目录.
这就是使用内置函数更安全的原因.
因此,为什么你应该使用subprocess而不是system.
Reu*_*ani 60
在执行命令时,在os
模块中使用os.system
或subprocess
模块更喜欢Python更具体的方法有四种情况:
os
模块中的许多方法都可以在多个平台上使用,而许多shell命令是特定于操作系统的.os
模块中的特定方法来避免.您实际上是在执行最终系统调用的过程chmod
中执行冗余的"中间人"(在您的示例中).这个中间人是一个新的过程或子壳.
来自os.system
:
在子shell中执行命令(字符串)...
并且subprocess
只是一个产生新流程的模块.
您可以在不产生这些过程的情况下完成所需的操作.
该os
模块的目的是提供通用的操作系统服务,它的描述始于:
该模块提供了一种使用操作系统相关功能的便携方式.
您可以os.listdir
在Windows和unix上使用.尝试使用os.system
/ subprocess
用于此功能将强制您维护两个调用(对于ls
/ dir
)并检查您正在使用的操作系统.这不是那么便携,以后会引起更多的挫折(参见处理输出).
假设您要列出目录中的文件.
如果您正在使用os.system("ls")
/ subprocess.call(['ls'])
,则只能返回进程的输出,这基本上是带有文件名的大字符串.
如何从两个文件中告诉一个带有空格的文件?
如果您没有列出文件的权限怎么办?
你应该如何将数据映射到python对象?
这些只是我的头脑,虽然有这些问题的解决方案 - 为什么再次解决一个为你解决的问题?
这也是继的例子不要重复自己原则通过(通常下文称"干")不重复已经存在,并且是免费提供给你一个实现.
os.system
并且subprocess
很强大.当你需要这种力量时它很好,但是当你不需要它时它会很危险.当您使用时os.listdir
,您知道它除了列出文件或引发错误之外无法执行任何其他操作.当您使用os.system
或subprocess
实现相同的行为时,您可能最终会做一些您不想做的事情.
注射安全性(见壳注射实例):
如果你使用来自用户的输入作为新命令,你基本上给了他一个shell.这很像SQL注入,在DB中为用户提供shell.
一个例子是表单的命令:
# ... read some user input
os.system(user_input + " some continutation")
Run Code Online (Sandbox Code Playgroud)
这可以很容易利用来运行任何使用输入任意代码:NASTY COMMAND;#
创建最终的:
os.system("NASTY COMMAND; # some continuation")
Run Code Online (Sandbox Code Playgroud)
有许多此类命令可能会使您的系统面临风险.
vol*_*ano 23
原因很简单 - 当你调用shell函数时,它会创建一个子shell,在命令存在后会被销毁,所以如果你在shell中更改目录 - 它不会影响Python中的环境.
此外,创建子shell非常耗时,因此直接使用OS命令会影响您的性能
编辑
我有一些运行时间测试:
In [379]: %timeit os.chmod('Documents/recipes.txt', 0755)
10000 loops, best of 3: 215 us per loop
In [380]: %timeit os.system('chmod 0755 Documents/recipes.txt')
100 loops, best of 3: 2.47 ms per loop
In [382]: %timeit call(['chmod', '0755', 'Documents/recipes.txt'])
100 loops, best of 3: 2.93 ms per loop
Run Code Online (Sandbox Code Playgroud)
内部功能运行速度提高10倍以上
EDIT2
可能有些情况下,调用外部可执行文件可能会产生比Python包更好的结果 - 我只记得我的同事发送的邮件,通过子进程调用的gzip的性能远高于他使用的Python包的性能.但当我们谈论模拟标准OS命令的标准OS包时,当然不是
小智 16
Shell调用是特定于操作系统的,而在大多数情况下,Python os模块函数不是.它避免产生子进程.
MSa*_*ers 11
效率更高."shell"只是另一个包含大量系统调用的OS二进制文件.为什么只为单个系统调用产生创建整个shell进程的开销?
当你使用os.system
不是内置shell的东西时情况会更糟.你启动一个shell进程,然后启动一个可执行文件,然后(两个进程)进行系统调用.至少subprocess
可以消除对shell中间过程的需求.
这不是Python特有的.systemd
对Linux启动时间的改进是出于同样的原因:它使得必要的系统调用本身而不是产生一千个shell.
归档时间: |
|
查看次数: |
26508 次 |
最近记录: |