使用带有sed命令的os.system()时出现问题

时间:2009-07-01 12:11:38

标签: python

我正在编写一个小方法来替换文件中的某些文本。 我需要的唯一参数是新文本,因为它总是与要替换的文件和文本相同。

当我尝试使用方法的参数时,我在使用os.system()调用时遇到问题

如果我使用如下字符串,一切运行正常:

stringId = "GRRRRRRRRR"
cmd="sed '1,$s/MANAGER_ID=[0-9]*/MANAGER_ID=" + stringId + "/g' path/file.old > path/file.new"
os.system(cmd)

现在,如果我尝试将字符串作为下面的参数,则不执行该命令。 我做了一个打印,看看命令是否正确,它是。如果我复制/粘贴到我的shell

,我甚至可以成功执行它
import os
def updateExportConfigId(id):
stringId = "%s" % id
cmd= "sed '1,$s/MANAGER_ID=[0-9]*/MANAGER_ID=" + stringId + "/g' path/file.old > path/file.new"
print "command is " + cmd
os.system(cmd)

有谁知道出了什么问题?

由于

7 个答案:

答案 0 :(得分:5)

强制性:不使用os.system - 使用subprocess模块:

import subprocess

def updateExportConfigId(m_id, source='path/file.old', 
                             destination='path/file.new'):
    if isinstance(m_id, unicode):
        m_id = m_id.encode('utf-8')
    cmd= [
          "sed",
          ",$s/MANAGER_ID=[0-9]*/MANAGER_ID=%s/g" % m_id,  
          source,
         ]
    subprocess.call(cmd, stdout=open(destination, 'w'))

使用此代码可以传递管理员ID,它可以包含空格,引用字符等。文件名也可以传递给函数,也可以包含空格和其他一些特殊字符。那是因为你的shell没有被不必要地调用,所以在你的操作系统上启动了少一个进程,你不必担心转义特殊的shell字符。

另一种选择:不要启动sed。使用python的re模块。

import re
def updateExportConfigID(m_id, source, destination):
    if isinstance(m_id, unicode):
        m_id = m_id.encode('utf-8')
    for line in source:
        new_line = re.sub(r'MANAGER_ID=\d*', 
                          r'MANAGER_ID=' + re.escape(m_id), 
                          line)
        destination.write(new_line)

并将其称为:

updateExportConfigID('GRRRR', open('path/file.old'), open('path/file.new', 'w'))

无需新流程。

答案 1 :(得分:2)

为了帮助您调试它,请尝试添加:

print repr(cmd)

当您复制并粘贴普通打印件时,可能会出现一些特殊字符滑入命令。

答案 2 :(得分:1)

错误的是存在一些差异。是的,我知道这没有用,但你需要找出差异。

尝试运行:

import os
def updateExportConfigId(id):
    stringId = "%s" % id
    cmd1 = "sed '1,$s/MANAGER_ID=[0-9]*/MANAGER_ID=" + stringId + "/g' path/file.old > path/file.new"
    stringId = "GRRRRRRRRR"
    cmd2 = "sed '1,$s/MANAGER_ID=[0-9]*/MANAGER_ID=" + stringId + "/g' path/file.old > path/file.new"

    print "cmd1:" , cmd1
    print "cmd2:" , cmd2
    print cmd1 == cmd2

updateExportConfigId("GRRRRRRRRR")

代码应打印:

sed '1,$s/MANAGER_ID=[0-9]*/MANAGER_ID=GRRRRRRRRR/g' path/file.old > path/file.new
sed '1,$s/MANAGER_ID=[0-9]*/MANAGER_ID=GRRRRRRRRR/g' path/file.old > path/file.new
True

从而表明它们完全相同。如果最后一行是“假”,那么它们就不一样了,你应该能够看到差异。

答案 3 :(得分:1)

因此,从以前的答案我们现在知道id是一个Unicode字符串,它使cmd1成为一个Unicode字符串,os.system()将其转换为字节字符串,以便以默认编码执行。

a)我建议使用subprocess而不是os.system()

b)我建议不要将内置函数的名称用作变量(id)。

c)我建议在执行之前将字符串显式编码为字节字符串:

if isinstance(cmd,unicode):
    cmd = cmd.encode("UTF-8")

d)对于Lennart Regebro的建议,添加:

assert type(cmd1) == type(cmd2)

print cmd1 == cmd2

答案 4 :(得分:0)

也许有一些缩进问题?

以下工作正常:

import os

def updateExportConfigId(id):
    stringId = "%s" % id
    cmd= "sed '1,$s/MANAGER_ID=[0-9]*/MANAGER_ID=" + stringId + "/g' test.dat > test.new"
    print "command is " + cmd
    os.system(cmd)


updateExportConfigId("adsf")

也不要使用保留字(id)作为变量。

答案 5 :(得分:0)

仅使用raw strings可能会有所帮助。

答案 6 :(得分:0)

最后,我找到了运行os.system(cmd)的方法!

简单的技巧,“清理”cmd字符串:

os.system(str(cmd))

现在,我能够使用我需要的所有参数构建cmd,最后我使用str()调用“清理”它,然后使用os.system()调用运行它。

非常感谢您的回答!

SWON