Python Find(bash命令)不';不能使用子进程吗?

Python Find(bash命令)不';不能使用子进程吗?,python,sed,find,subprocess,xargs,Python,Sed,Find,Subprocess,Xargs,我在许多(python django)模板中重命名了css类名。但是,css文件广泛分布在多个目录中的多个文件中。我有一个python代码段从根目录开始重命名,然后递归地重命名所有css文件 from os import walk, curdir import subprocess COMMAND = "find %s -iname *.css | xargs sed -i s/[Ff][Oo][Oo]/bar/g" test_command = 'echo "This is just a t

我在许多(python django)模板中重命名了css类名。但是,css文件广泛分布在多个目录中的多个文件中。我有一个python代码段从根目录开始重命名,然后递归地重命名所有css文件

from os import walk, curdir
import subprocess

COMMAND = "find %s -iname *.css | xargs sed -i s/[Ff][Oo][Oo]/bar/g"
test_command = 'echo "This is just a test. DIR: %s"'

def renamer(command):
  print command  # Please ignore the print commands.
  proccess = subprocess.Popen(command.split(), stdout = subprocess.PIPE)
  op = proccess.communicate()[0]
  print op

for root, dirs, files in walk(curdir):
  if root:
    command = COMMAND % root
    renamer(command)
它不起作用,给出:

find ./cms/djangoapps/contentstore/management/commands/tests -iname *.css | xargs sed -i s/[Ee][Dd][Xx]/gurukul/g
find: paths must precede expression: |
Usage: find [-H] [-L] [-P] [-Olevel] [-D help|tree|search|stat|rates|opt|exec] [path...] [expression]

find ./cms/djangoapps/contentstore/views -iname *.css | xargs sed -i s/[Ee][Dd][Xx]/gurukul/g
find: paths must precede expression: |
Usage: find [-H] [-L] [-P] [-Olevel] [-D help|tree|search|stat|rates|opt|exec] [path...] [expression]
当我复制并运行相同的命令(上面打印)时,
find
不会出错,sed要么没有输入文件,要么工作正常


python代码段出了什么问题?

您尝试运行的不是单个命令,而是由多个命令组成的shell管道,并且您尝试在不调用shell的情况下运行它。那不可能。在执行此操作时,
|
只是
find
的参数之一,这就是为什么
find
告诉您它不理解带有“路径必须在表达式之前:|”错误的参数的原因

您可以通过将
shell=True
添加到您的
Popen
来修复此问题

但是一个更好的解决方案是在Python中执行管道,并且不使用shell。请参阅文档中的解释,但我将展示一个示例

同时,决不能使用
split
分割命令行。最好的解决方案是编写单独参数的列表,而不是将它们合并成一个字符串来拆分它们。如果必须这样做,请使用
shlex
模块;这就是它的目的。但在您的情况下,即使这样也帮不上忙,因为您正在逐字插入随机字符串,其中很容易包含空格或引号,并且没有任何东西-
shlex
或其他任何东西可以首先重建数据

因此:


但这里有一个更好的解决方案

Python有
os.walk
来做与
find
相同的事情,您可以轻松地模拟
xargs
,但实际上不需要这样做,它有自己的
re
模块来代替
sed
。那么,为什么不使用它们呢


或者,相反,bash比Python更擅长驱动和连接简单的命令,因此如果您更愿意使用
find
sed
而不是
os.walk
re.sub
,那么为什么首先要用Python编写驱动脚本呢?

问题在于管道。要将管道与子流程模块一起使用,您必须传递
shell=True

阿巴内特的答案比我的答案准确得多。这样做吧。你需要使用
shell=True
让管道工作。请参阅示例。在这种情况下,您不需要管道:
op=subprocess。检查_输出([“find”,root]+r“-iname\*.css-exec sed-i s/foo/bar/gi{}+”.split())
+1以获得好的答案,这两种方法都用示例显示正确的方法,并修复我的尝试。我现在意识到,在我的努力中,
find
os.walk
之间存在重叠,这只是令人遗憾的心不在焉。使用find and而不是os.walk的一个原因是find要快得多。虽然Python3.5+有一个新函数os.scandir,它使用相同的sys调用find does并具有与之相当的性能,但os.walk对每个文件都执行sys调用find@twneale实际上,
scandir
并没有使用与
find
相同的系统调用(至少在现代GNU和BSD系统上是这样)。那将是
fts
。(上次我检查时,有一个库为Python包装了
fts
,但我遇到了一些问题,所以我用
ctypes
编写了自己的不完整包装。现在可能有更好的了。)在FreeBSD上,
fts
可以快得多;在linux(至少对某些文件系统而言,lookahead缓存惊人)或OS X(其中一些关键优化在苹果的文件系统上不起作用)上,您可能可以使用
scandir
。但首先要确保确实存在性能问题…
pfind = Popen(['find', root, '-iname', '*.css'], stdout=PIPE)
pxargs = Popen(['xargs', 'sed', '-i', 's/[Ff][Oo][Oo]/bar/g'], 
               stdin=pfind.stdout, stdout=PIPE)
pfind.stdout.close()
output = pxargs.communicate()