我在一些(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片段有什么问题?
答案 0 :(得分:8)
您不是在尝试运行单个命令,而是尝试运行多个命令的shell管道,并且您尝试在不调用shell的情况下执行此操作。那不可能奏效。你这样做的方式,|
只是find
的一个参数,这就是为什么find
告诉你它不理解那个“路径必须在表达式前面:|“错误。
您可以通过向shell=True
添加Popen
来解决此问题。
但更好的解决方案是在Python中执行管道并保持shell不受其影响。有关说明,请参阅文档中的Replacing Older Functions with the subprocess
Module,但我会举例说明。
同时,您不应该使用split
来拆分命令行。最好的解决方案是编写单独的参数列表,而不是将它们连接成一个字符串,只是为了将它们拆分出来。如果必须这样做,请使用shlex
模块;这就是它的用途。但是在你的情况下,即使这样也无济于事,因为你逐字插入随机字符串,其中很容易有空格或引号,并且没有任何方法 - shlex
或其他 - 可以重建数据首先。
所以:
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()
但这里有一个更好的解决方案。
Python os.walk
与find
执行相同的操作,您可以轻松地模拟xargs
,但实际上没有必要这样做,并且它有自己的re
使用模块而不是sed
。那么,为什么不使用它们呢?
或者相反,bash在驱动和连接简单命令方面要比Python好得多,所以如果你宁愿使用find
和sed
而不是os.walk
和{{1为什么首先在Python中编写驱动脚本?
答案 1 :(得分:1)
问题是管道。要在子进程模块中使用管道,您必须传递shell=True
。