2015-10-23 49 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