【发布时间】:2015-01-16 23:26:11
【问题描述】:
我正在尝试为 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()
此代码将通过,因为直接 shell 命令和包装器创建的命令都将输出相同的结果。
现在,举个例子,在我看来是同类,但不起作用:
def test2():
cmd = """mdfind 'kMDItemKind=PDF&&kMDItemFSName="*epistem*"c'"""
shell_res = run_shell(cmd)
find_res = mdfind(kind='PDF',
name='"*epistem*"c')
直接 shell 命令将在我的机器上返回标题中包含“认识论”的单个 PDF,而 wrapper made 命令将返回 13 个 PDF(我的机器上总共有 1,000 多个 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() 为直接 shell 命令返回 1 个结果(我的意思是命令是字符串并且设置了shell=True),为 3 项列表命令返回 13 个结果,为 2 项列表命令返回 144 个结果?幕后发生了什么?如何让 3 项列表仅返回直接 shell 命令所做的一项?
【问题讨论】:
标签: python unix subprocess