2015-10-23 46 views
0

我正在研究Python脚本来比较两个文件。因此,我已选择了与grep工作作为外部程序,启动以下两个命令:subprocess.Popen输出:如何克服命令行执行的差异

grep -Fvf content1.txt content2.txt 
grep -Fvf content2.txt content1.txt 

从这些命令的结果给我的差异,我可以通过计数线量提取的差的量。

为了在Python脚本来执行这一点,我在subprocess.Popen()功能嵌入那些grep命令:

try: 
    output1, errors1 = subprocess.Popen(
     ["c:\\cygwin\\bin\\grep", "-Fvf", "content1.txt", "content2.txt"], 
     shell=True, stdout=PIPE, stderr=PIPE).communicate() 

    output2, errors2 = subprocess.Popen(
     ["c:\\cygwin\\bin\\grep", "-Fvf", "content2.txt", "content1.txt"], 
     shell=True, stdout=PIPE, stderr=PIPE).communicate() 

    if (len(output1) + len(output2) + len(errors1) + len(errors2) > 0): 
     print("Result : there are differences:") 

     if (len(output1) + len(output2) > 0): 
      print(" Output differences : ") 
      print(output1) 
      # print (str(str(output1).count('\n'))); (*) 
      print(output2) 
      # print (str(str(output2).count('\n'))); (*) 
      if (len(errors1) + len(errors2) > 0): 
       print(" Errors : ") 
       print(errors1) 
       print(errors2) 
      else: 
       print("Result : both are equal") 

except Exception as ex: 
    print("Result : Exception during comparison:") 
    print(ex) 
    raise 

我已经把在评论这两个问题的线(谁与(*)结束的)。

正如你所看到的问题如下:

  • 当我在命令提示符启动命令,这是我得到的结果是一串字符串。通过计算这些字符串的数量,我可以得到我想要的结果(例如使用wc -l)。

  • 当我在Python脚本中启动命令时,得到的结果(output1output2)是字节而不是字符串。

    我曾希望对字符串进行简单的类型转换可以让我有机会计算换行符的数量,并计算差异的数量,但这太容易了。

我已经使用wc -lsubprocess.Popen()管道内部尝试似乎不是一个好主意。

如何处理output1output2结果以便搜索差异数量?

+0

我看到你正在使用cygwin,你可能想尝试在subprocess.Popen调用中添加'universal_newlines = True'。 – secolive

+1

你有没有使用外部grep而不是来自标准库的'difflib'模块的特殊原因? –

+0

你好,Serge,我是一个Python新手,我不知道'difflib'模块,我已经试过'filecmp',但是我并不满意。现在我将更近距离观察'difflib'。感谢您的提议。 – Dominique

回答

0

我猜你正在使用python 3.x(你不指定2.7 vs 3.x,但在2.7中,subprocess.communicate()返回一个包含两个字符串或无值的元组,但在3.x中返回两个字节或无值的元组,你说特别是“字节”):

$ python3 
... 
>>> import subprocess 
>>> proc = subprocess.Popen(['ls'], stdout=subprocess.PIPE) 
>>> res = proc.communicate()[0] 
>>> type(res) 
<class 'bytes'> 
>>> 

VS:

$ python2 
... 
>>> import subprocess 
>>> proc = subprocess.Popen(['ls'], stdout=subprocess.PIPE) 
>>> res = proc.communicate()[0] 
>>> type(res) 
<type 'str'> 
>>> 

这是因为python3使用Unicode对其所有字符串(而不是试图为字节序列和“粘性”事物使用字符串)。

有两种明显的方法可以解决这个问题。

  • 与字节字节工作:

    >>> res.count(b'\n') 
    382 
    >>> print(res.splitlines())[0]) 
    b'COPYING' 
    

    (此方法也适用于Python 2.7版中,B '\ n' 只是 '\ n')。

  • 转换输入到Unicode。我不是很Python3起来,我不知道最好的方式做到这一点的,但这似乎还不错:

    >>> stringy = res.decode('utf-8') # or whatever encoding your system uses 
    >>> print(type(stringy), stringy.splitlines()[0]) 
    <class 'str'> COPYING 
    

或者,您可以通过Python的管道输出转换为Unicode字符串设置universal_newlines=True;见the documentation

或者,当然,你可以使用Python 2 :-)(我还是做了各种兼容的原因)

+0

谢谢你解决我的问题:我确实使用Python 3,并使用以下命令已解决我的问题:'print(str(output1.count(b' \ n')));' (mind b“\ n”,而不是“\ n”) – Dominique

+0

'splitlines(ord(b'\ n'))'是误导性的。该参数是一个布尔类型'keepends',即,您想要'splitlines(True)'而不是。另外,编写在Python 2和Python 3上相同的代码很容易,例如'.count(b'\ n')'可以在Python 2.7和Python 3上运行,或者通过'universal_newlines = True'启用文本模式。 – jfs

+0

@ J.F.Sebastian:嗯,正如我所说的,我对Python 3不太了解。将会更新答案。 – torek

0

你为什么不管它的UNIX工具diff

diff <(grep "^@" myfile1) <(grep "^@" myfile2) 

您可以在popen命令调用它。

+0

我正在使用Windows 7环境,其中包含“grep”工具的“C:\ Cygwin”目录。不过,我似乎没有“差异”工具。 – Dominique

+1

然后从setup.exe安装它。 diff是cygwin中不可或缺的工具。 –

+0

@Dominique可能将这些添加到您的问题是一个好主意:) –

0

不要字节调用str()。这几乎总是一个错误。

要启用文本模式,请将universal_newlines=True传递给subprocess.Popen()

或者您可以直接使用字节,例如使用.count(b'\n')而不是.count('\n')

+0

有什么理由downvote? – jfs

+0

我不知道谁低估了,但我反制衡了它。 – torek