在 Mac OS X 终端中,如何确定一个目录是捆绑包还是包?

5

我希望能够在命令行上从Finder的角度确定一个目录(例如'.app')是否被视为包或捆绑包。我认为使用一个小的shell程序来完成这个任务并不难,但如果不必要的话,我不想重新发明轮子。


我想要一些澄清。从下面的答案中,人们会认为“文件系统中没有捆绑位”实际上并未设置捆绑目录,只有Finder知道根据逻辑和启发式呈现它们作为文件,并注册特定的“文件名扩展名”。这是真的吗?我一直在到处寻找如何确定一个目录是否是捆绑包(以编程方式,Obj-C)在“Unix”方面 - 给定一个文件/目录的“stat”结构,但无济于事。真相在哪里? - Motti Shneor
6个回答

10

可能有点晚了,但是:似乎你可以使用mdls命令来检测bundle。具体来说,是通过以下(多行)输出进行的:

mdls -name kMDItemContentTypeTree /Path/To/Directory

将包含该字符串

"com.apple.package"

在Lion版本中,如果目录是一个包(package),那么输出的结果会至少包括双引号。如果这个包同时也是一个捆绑(bundle),那么输出的结果还会包含其他内容。

"com.apple.bundle"

而且,最后但并非最不重要的,如果它是一个应用程序捆绑包,输出也将包含

"com.apple.application-bundle"

(这是根据一些非常有限的测试得出的,但根据苹果关于统一类型标识符的文档和mdls的手册,这应该是正确的。对于我测试过的项目,对于非苹果提供的捆绑包也是如此,鉴于UTI的目的,这是你所期望的。)


4

虽然你可以通过存在 './contents/Info.plist' 来识别一些捆绑包,但并不是所有类型的捆绑包都需要这个文件(例如文档和旧版捆绑包)。Finder 还可以根据文件扩展名(.app、.bundle 等)或者捆绑包位是否设置来将目录识别为捆绑包。

要从命令行检查捆绑包位,请使用:

getFileInfo -aB directory_name

为了涵盖所有情况,我会检查以下内容:
  • 捆绑位是否设置?
  • 如果没有设置,它是否具有将其标识为捆绑的文件扩展名?(参见Mecki的答案
  • 如果没有,则可能不是一个捆绑。

4

更新:

对于所有带有 Spotlight 的系统,您可以使用 mdls 命令检测包。查看 kMDItemContentTypeTree 属性即可。例如:

mdls -name kMDItemContentTypeTree "/Applications/Safari.app"

我为您产生以下输出结果:

对我来说,会产生以下输出结果

kMDItemContentTypeTree = (
    "com.apple.application-bundle",
    "com.apple.application",
    "public.executable",
    "com.apple.localizable-name-bundle",
    "com.apple.bundle",
    "public.directory",
    "public.item",
    "com.apple.package"
)

无论何时你看到 com.apple.package,它都应该被Finder显示为一个包。当然,所有带有“bundle”名称的东西都已经暗示了这一点,但并不是所有的包都是捆绑包(捆绑包是具有明确定义的目录结构的包的特定子集)。

旧答案:

你可以使用以下命令(Leopard之前的OS X版本)获取所有注册文件类型扩展名的列表:

/System/Library/Frameworks/ApplicationServices.framework/Frameworks\
/LaunchServices.framework/Support/lsregister -dump

或者适用于Leopard及更高版本:

/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks\
/LaunchServices.framework/Versions/A/Support/lsregister -dump

每个文件扩展名都有标志。如果设置了包标志,那么这是一个包。
例如:
  claim   id:            806354944
            name:          Bundle
            role:          none
            flags:         apple-internal  relative-icon-path  package  
            icon:          Contents/Resources/KEXT.icns
            bindings:      .bundle
    --------------------------------------------------------
    claim   id:            1276116992
            name:          Plug-in
            role:          none
            flags:         apple-internal  relative-icon-path  package  
            icon:          Contents/Resources/KEXT.icns
            bindings:      .plugin

将此与非捆绑文件进行比较

    claim   id:            2484731904
            name:          TEXT
            role:          viewer
            flags:         apple-internal  
            icon:          
            bindings:      .txt, .text, 'TEXT'

唯一真正获取所有bundle的方法是查找LaunchService数据库(即我们上面转储的那个)。如果您仅按照它是否有plist或者是否设置了bundle位来判断,可能会捕获一些甚至很多bundles,但您无法捕获所有的bundles。这是Finder用于确定以下内容的数据库:
  • 这个目录是bundle还是其他文件?
  • 这是已知的文件扩展名吗?
  • 对于此文件类型,应列出哪些应用程序在“打开方式”下?
  • 我应该使用哪个图标来显示此文件类型?

以及其他一些内容。

[编辑:感谢Hagelin更新,添加了Leopard的路径]


在Leopard系统中,该命令为: "/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister -dump"。 - Hagelin

1

<插件>

我的启动工具有这个功能。例如:

% launch -f Guards.oo3 
Guards.oo3: non-application package 
    type: ''    creator: ''
    kind: OmniOutliner 3
    content type ID: com.omnigroup.omnioutliner.oo3-package
    contents: 1 item
    created: 3/6/09 3:36:50 PM
    modified: 3/6/09 4:06:13 PM
    accessed: 4/12/09 1:10:36 PM [only updated by Mac OS X]
    backed up: 12/31/03 6:00:00 PM

% launch -f /Applications/Safari.app
/Applications/Safari.app: scriptable Mac OS X application package 
    type: 'APPL'    creator: 'sfri'
    architecture: PowerPC 7400, Intel 80x86
    bundle ID: com.apple.Safari
    version: 4 Public Beta
    kind: Application
    content type ID: com.apple.application-bundle
    contents: 1 item
    created: 8/21/07 5:11:33 PM
    modified: 2/24/09 7:29:51 PM
    accessed: 4/12/09 1:10:51 PM [only updated by Mac OS X]
    backed up: 12/31/03 6:00:00 PM

通过检查输出的第一行是否以“package”结尾,您应该能够获得所需的内容。

launch也在Fink和MacPorts中。

</plug>


0

应该有一种从命令行轻松完成它的方法,因为作为一个AppleScript用户,我可以使用系统事件来完成它。因此,如果所有其他方法都失败了,您可以按以下方式从命令行执行必要的AppleScript:

$ FILE=/Users/myuser/Desktop/foo.rtfd
$ osascript -e "tell application \"System Events\" to get package folder of alias POSIX file \"${FILE}\""

结果是

true

-2
一个 bundle 应该总是有一个文件 `./contents/Info.plist'。您可以在目录中检查其是否存在,如果存在,则为 package/bundle。

应用程序通常都有一个 contents/Info.plist 文件,但这并不是包或捆绑包的必要条件。大多数文档捆绑包都没有这种结构。 - amrox
没错。到目前为止,我的研究表明对于像文档包这样的东西,Finder 依赖于目录名中使用的“扩展名”。 - Joseph Daigle
这是不正确的,不是每个捆绑包都有一个plist。 - Mecki

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接