簡體   English   中英

使用Python子進程的mdfind結果不同的原因

[英]Reason for disparate results with mdfind using Python subprocess

我正在嘗試為UNIX mdfind實用程序編寫Python包裝器。 以最簡單的形式,它運作良好; 但是,我無法弄清一個奇怪行為的例子。 當運行更復雜的查詢(兩個或多個字段)時,事情變得有些奇怪。 請看以下示例:

import subprocess
import itertools

def test1():
    cmd = "mdfind 'kMDItemFSName=pandoc&&kMDItemContentType=public.unix-executable'"
    shell_res = subprocess.check_output(cmd, shell=True)
    find_res = mdfind(content_type='public.unix-executable',
                      name='pandoc')
    if shell_res == find_res:
        print('Passed!')

def mdfind(**kwargs):
    cmd = ['mdfind']
    for key, arg in kwargs.iteritems():
        if key in mdattributes().keys():
            md_name = mdattributes()[key]['id']
            query = '='.join([md_name, arg])
            cmd.append(query)
    if 'only_in' in kwargs:
        cmd.append('-onlyin')
        cmd.append(kwargs['only_in'])
    return subprocess.check_output(cmd)

def mdattributes():
    attributes_str = subprocess.check_output(['mdimport', '-A'])
    # prepare key names for the four columns
    keys = ('id', 'name', 'description', 'aliases')
    # create list of dicts, mapping ``keys`` to an item's columns
    data = [dict(itertools.izip(keys,
                                [item.replace("'", "")
                                 for item in attribute.split('\t\t')]))
            for attribute in attributes_str.splitlines()]
    # coerce list of dicts into large dict with nested dicts
    metadata = {}
    for md_dict in data:
        # clean up key
        key = md_dict['id'].replace('kMDItemFS', '')\
                           .replace('kMDItem', '')\
                           .replace('kMD', '')\
                           .replace('com_', '')
        metadata[key] = md_dict
    return metadata

test1()

該代碼將通過,因為直接外殼程序命令和包裝器創建的命令將輸出相同的結果。

現在,以這個示例為例,在我看來,這種示例是相同的,但不起作用:

def test2():
    cmd = """mdfind 'kMDItemKind=PDF&&kMDItemFSName="*epistem*"c'"""
    shell_res = run_shell(cmd)
    find_res = mdfind(kind='PDF',
                      name='"*epistem*"c')

Straight Shell命令將在我的機器上返回標題中帶有“認識論”的單個PDF,而wrapper made命令將返回13個PDF(我的機器上總共有1000多個PDF)。 因此,包裝器腳本以某種方式過濾了數千個PDF,但顯然不是通過標題中是否包含*epistem*來過濾。

更奇怪的是,此命令將返回144個結果:

subprocess.check_output(['mdfind',
                          """kMDItemKind=PDF&&kMDItemFSName="*epistemolog*"c"""])

因此,簡而言之,這三個不同的子流程調用給出的結果數量完全不同:

"""mdfind 'kMDItemKind=PDF&&kMDItemFSName="*epistem*"c'"""
['mdfind', 'kMDItemKind=PDF', u'kMDItemFSName="*epistem*"c']
['mdfind', """kMDItemKind=PDF&&kMDItemFSName="*epistemolog*"c"""]

所以,我的問題是:為什么? 為什么subprocess.check_output()對於純外殼程序命令返回1個結果(我的意思是該命令是字符串,並且已設置shell=True ),對於3項列表命令返回13個結果,而對2項列表命令返回144個結果? 幕后到底是怎么回事? 如何獲得3項列表,僅返回直線外殼命令所做的一項?

我確信這與命令行參數處理管道中的細微但重要的差異有關。 該管道很復雜,並且從編程語言環境中調用命令時,實際上很難獲得在您喜歡的shell中鍵入命令時等效的行為。

壞事是:取決於目標可執行文件用於解析命令行參數的方法(不幸的是-在許多情況下-沒有確定的標准),結果可能因調用方法而異。 也就是說,您的觀察肯定與空格,NULL字符,破折號和引號的處理和解釋有關。

您的問題是“為什么?”。 因此,如果您真的想深入了解這一點,則需要查看Python子過程模塊的源代碼以及目標命令命令行參數解析代碼的源代碼。 另外,您可能希望讀取以下內容:

為了獲得在外殼程序中鍵入時在概念上等效的行為,有一個非顯而易見但簡單的解決方法:創建一個臨時外殼程序腳本並從Python內部調用您的外殼程序,並僅提供一個參數:外殼程序腳本的路徑。 我已在此模塊中使用此方法來創建系統的命令行工具測試: https : //github.com/jgehrcke/timegaps/blob/master/test/clitest.py

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM