<p>在执行命令时,在<a href="https://docs.python.org/2/library/os.html">^{<cd1>}</a>模块中优先使用Python更具体的方法的情况有四种:</p>
<ul>
<li><strong>冗余</strong>-生成另一个进程是冗余的,浪费时间和资源。</li>
<li><strong>可移植性</strong>-模块中的许多方法在多个平台上可用,而许多shell命令是操作系统特有的。</li>
<li><strong>了解结果</strong>-生成一个进程来执行任意命令会迫使您分析输出结果,并了解如果</strong>和</strong>为什么</strong>某个命令做错了什么。</li>
<li><strong>安全性</strong>-进程可以潜在地执行其给定的任何命令。这是一个弱设计,可以通过在<code>os</code>模块中使用特定的方法来避免。</li>
</ul>
<h2>冗余(见<a href="http://en.wikipedia.org/wiki/Redundant_code"><em>redundant code</em></a>):</h2>
<p>实际上,您正在执行一个多余的“中间人”以到达最终的系统调用(在您的示例中是<code>chmod</code>)。这个中间人是一个新的过程或子壳。</p>
<p>来自<a href="https://docs.python.org/2/library/os.html#os.system">^{<cd2>}</a>:</p>
<blockquote>
<p>Execute the command (a string) in a subshell ...</p>
</blockquote>
<p>而<a href="https://docs.python.org/2/library/subprocess.html">^{<cd3>}</a>只是一个生成新进程的模块。</p>
<p>你可以做你需要的,而不产生这些过程。</p>
<h2>可移植性(见<a href="http://en.wikipedia.org/wiki/Software_portability#Source_code_portability"><em>source code portability</em></a>):</h2>
<p><a href="https://docs.python.org/2/library/os.html">^{<cd1>}</a>模块的目标是提供通用操作系统服务,它的描述以以下开头:</p>
<blockquote>
<p>This module provides a portable way of using operating system dependent functionality.</p>
</blockquote>
<p>在windows和unix上都可以使用<a href="https://docs.python.org/2/library/os.html#os.listdir">^{<cd10>}</a>。尝试为此功能使用<code>os.system</code>/<code>subprocess</code>将强制您维护两个调用(用于<code>ls</code>/<code>dir</code>),并检查您所使用的操作系统。这不是很方便,而且以后会导致更大的挫败感(请参见处理输出)。</p>
<h2>了解命令的结果:</h2>
<p>假设要列出目录中的文件。</p>
<p>如果使用的是<code>os.system("ls")</code>/<code>subprocess.call(['ls'])</code>,则只能返回进程的输出,这基本上是一个带有文件名的大字符串。</p>
<p>你怎么能从两个文件中分辨出一个名字中有空格的文件?</p>
<p>如果你没有权限列出这些文件呢?</p>
<p>应该如何将数据映射到python对象?</p>
<p>这些只是我脑子里想出来的,虽然有解决这些问题的办法——为什么还要再解决一个为你解决的问题呢?</p>
<p>这是遵循<a href="http://en.wikipedia.org/wiki/Don't_repeat_yourself">Don't Repeat Yourself</a>原则(通常被称为“DRY”)的一个例子,方法是<strong>不</strong>重复一个已经存在并且可以免费获得的实现。</p>
<h2>安全性:</h2>
<p><code>os.system</code>和<code>subprocess</code>功能强大。当你需要这种能力的时候是好的,但是当你不需要的时候是危险的。当你使用<code>os.listdir</code>的时候,你知道</strong>除了列出文件或引发错误之外,它不能做任何其他事情。当你使用<code>os.system</code>或<code>subprocess</code>来实现相同的行为时,你可能最终会做一些你不想做的事情。</p>
<p><strong>注射安全性(见<a href="http://en.wikipedia.org/wiki/Code_injection#Shell_injection"><em>shell injection examples</em></a>)</strong>:</p>
<p>如果将用户输入用作新命令,基本上就是给了他一个shell。这与SQL注入在DB中为用户提供shell非常相似。</p>
<p>例如,命令的形式如下:</p>
<pre><code># ... read some user input
os.system(user_input + " some continutation")
</code></pre>
<p>这很容易被利用来运行任意代码,使用输入:<code>NASTY COMMAND;#</code>来创建最终的:</p>
<pre><code>os.system("NASTY COMMAND; # some continuation")
</code></pre>
<p>有许多这样的命令会使您的系统处于危险之中。</p>