Python 将os.system()与sed命令一起使用时出现问题

Python 将os.system()与sed命令一起使用时出现问题,python,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) 现在

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

当我尝试使用该方法的参数时,在使用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)
有人知道怎么回事吗


谢谢

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

print repr(cmd)

可能是在复制和粘贴时,普通打印隐藏的命令中包含了一些特殊字符。

可能是缩进问题

以下各项工作正常:

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
)作为变量。

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

尝试运行以下命令:

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

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

也许只使用它会有所帮助。

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

a) 我建议使用子流程而不是os.system()

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

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

if isinstance(cmd,unicode):
    cmd = cmd.encode("UTF-8")
d) 对于Lennart Regebro的建议,添加:

assert type(cmd1) == type(cmd2)
之后


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

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

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

非常感谢你的回答


swon

强制性:不要使用操作系统。
系统
-使用模块:

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

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

这样称呼它:

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

不需要新的流程。

我已经尝试过了,结果是一样的。使用print repr(cmd),我可以看到这两种情况之间存在差异:cmd='mv test.dat test.+stringId打印repr(cmd)的输出是:u'mv test.dat test.new',其中我使用了“new”字符串作为参数,但如果cmd=“sed”1,$s/MANAGER_ID=[0-9]*/MANAGER_ID=“+stringId+”/g'test.dat>test.new打印repr(cmd)的输出是:u“sed'1,$s/MANAGER\u ID=[0-9]*/MANAGER\u ID=adsf/g'test.dat>test.new”我尝试了所有字符串组合,使用了“”,“%s”,“+”+”“,…在解释这两种情况之间的差异时,尝试实际使用相同的示例。我能看到这两种情况之间的唯一区别是使用完全不同的命令。这没什么帮助。为了正确起见,
id
不是保留字。它是一个内置函数。不使用它们的意义仍然适用。只是一个简短的提示。stringId=“%s”%id行完全无用。%s“%id”与str(id)完全相同,如果id是字符串(在您的示例中应该是字符串),那么它本身当然是无用的。您正在运行哪一版本的Python?除了遵循更改id变量名和删除stringID行(以及在我的系统上设置合法值的路径)的建议之外,我让您的代码在Python 2.4.3上运行良好,即使没有str(cmd)。还有一件事,按照设置的方式,您将更改MANAGER\u ID=some\u ID的所有出现次数。如果您的文件中只有一个MANAGER\u ID,可能这就是您想要的,但是如果您的文件中有多个MANAGER\u ID,您将把它们都设置为相同的值。嗯,我真的很生气。。我测试过,字符串是一样的。区别仅出现在print repr()print repr(command1):u“sed”1,$s/MANAGER\u ID=[0-9]*/MANAGER\u ID=GRRRR/g”file.old>file.new“print repr(cmd2):“sed”1,$s/MANAGER\u ID=[0-9]*/MANAGER\u ID=GRRRR/g”file.old>file.new“在这种情况下,cmd2使用硬编码字符串,我可以通过os.system()调用运行cmd2。ThanksAha,所以区别在于第一种情况是unicode,另一种情况是字符串。出于某种原因,用unicode调用os.system()是行不通的。这一定意味着传入方法的变量id是unicode。
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'))
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'))