我试图理解使用Python库函数执行操作系统特定任务(如创建文件/目录、更改文件属性等)背后的动机,而不是仅仅通过os.system()
或subprocess.call()
执行这些命令?
例如,为什么我要使用os.chmod
而不是os.system("chmod...")
?
我知道,尽可能多地使用Python可用的库方法,而不是直接执行shell命令,会更加“pythonic”。但是,从功能的角度来看,这样做背后还有其他动机吗?
我只是在说执行简单的单行shell命令。当我们需要对任务的执行进行更多的控制时,我理解使用subprocess
模块更有意义,例如。
这样比较安全。下面是一个脚本示例
如果用户的输入是
test; rm -rf ~
,那么将删除主目录。这就是为什么使用内置函数更安全的原因。
因此,为什么您也应该使用子流程而不是系统。
它可以更快地创建新的进程,这对于这种简单的事情来说是不必要的。实际上,带有
shell
参数的os.system
和subprocess.call
通常会创建至少两个新进程:第一个进程是shell,第二个进程是您正在运行的命令(如果它不是像test
那样的shell内置进程)。有些命令在单独的过程中是无用的。例如,如果运行
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"])
也是如此。因为Python的标准库应该为您处理这些问题,所以跨平台和跨shell的关注点更少。您的系统是否有
chmod
命令?是否已安装?它是否支持您希望它支持的参数?如果不可能的话,os
模块将尝试尽可能跨平台和文档。如果您运行的命令有您关心的输出,您需要解析它,这比听起来更难,因为您可能会忘记角大小写(文件名中有空格、制表符和换行符),即使您不关心可移植性。
在执行命令时,在^{} 模块中优先使用Python更具体的方法的情况有四种:
os
模块中使用特定的方法来避免。冗余(见redundant code):
实际上,您正在执行一个多余的“中间人”以到达最终的系统调用(在您的示例中是
chmod
)。这个中间人是一个新的过程或子壳。来自^{} :
而^{} 只是一个生成新进程的模块。
你可以做你需要的,而不产生这些过程。
可移植性(见source code portability):
^{} 模块的目标是提供通用操作系统服务,它的描述以以下开头:
在windows和unix上都可以使用^{} 。尝试为此功能使用
os.system
/subprocess
将强制您维护两个调用(用于ls
/dir
),并检查您所使用的操作系统。这不是很方便,而且以后会导致更大的挫败感(请参见处理输出)。了解命令的结果:
假设要列出目录中的文件。
如果使用的是
os.system("ls")
/subprocess.call(['ls'])
,则只能返回进程的输出,这基本上是一个带有文件名的大字符串。你怎么能从两个文件中分辨出一个名字中有空格的文件?
如果你没有权限列出这些文件呢?
应该如何将数据映射到python对象?
这些只是我脑子里想出来的,虽然有解决这些问题的办法——为什么还要再解决一个为你解决的问题呢?
这是遵循Don't Repeat Yourself原则(通常被称为“DRY”)的一个例子,方法是不重复一个已经存在并且可以免费获得的实现。
安全性:
os.system
和subprocess
功能强大。当你需要这种能力的时候是好的,但是当你不需要的时候是危险的。当你使用os.listdir
的时候,你知道除了列出文件或引发错误之外,它不能做任何其他事情。当你使用os.system
或subprocess
来实现相同的行为时,你可能最终会做一些你不想做的事情。注射安全性(见shell injection examples):
如果将用户输入用作新命令,基本上就是给了他一个shell。这与SQL注入在DB中为用户提供shell非常相似。
例如,命令的形式如下:
这很容易被利用来运行任意代码,使用输入:
NASTY COMMAND;#
来创建最终的:有许多这样的命令会使您的系统处于危险之中。
相关问题 更多 >
编程相关推荐