如何以编程方式将 OS X“标签”添加到文件中?

Posted

技术标签:

【中文标题】如何以编程方式将 OS X“标签”添加到文件中?【英文标题】:How can I add OS X "tags" to files programmatically? 【发布时间】:2013-11-12 06:38:45 【问题描述】:

自 Mavericks 以来,OS X 已经能够在 Finder 中标记和着色文件。

有没有办法通过 Cocoa API 或通过 shell 命令向文件添加标签?

【问题讨论】:

见related question。你说的是哪种标签?我会在下面给出标签颜色的答案,但是关键字和聚光灯标签有点不同。 @beroe 我最初对这种能力感到好奇,因为我认为在我的 xCode 构建阶段添加一个构建步骤会很好,该构建步骤将标记构建目录,以便在 finder 中轻松搜索。我在related question 中看到了您接受的答案,但我没有使用 python 的经验,您能否提供一个可以像着色一样在文件上运行的脚本? 好的,我添加了一个框架脚本,可以让你用一个词来标记文件夹或文件... 【参考方案1】:

很抱歉添加另一个答案,但与设置标签颜色相关的答案已经很长了。这是我用来设置用户标签的 python 脚本的摘录。它似乎可以使事物可搜索,但不确定标签是否会正确显示。用法基本上是:

tagfile.py "Tag Name" FileOrFolderName

代码如下。

#! /usr/bin/env python
# -*- coding: utf-8 -*-

""" Write tags to file
Usage:
    tagfile.py "TagName" FileName1 FileName2 

    You can use wildcards for the file name. Use quotes if spaces in tags.
    To check if it worked, use xattr -l FileName

"""

import sys
import subprocess

def writexattrs(F,TagList):
    """ writexattrs(F,TagList):
    writes the list of tags to three xattr fields on a file-by file basis:
    "kMDItemFinderComment","_kMDItemUserTags","kMDItemOMUserTags
    Uses subprocess instead of xattr module. Slower but no dependencies"""

    Result = ""

    plistFront = '<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"><plist version="1.0"><array>'
    plistEnd = '</array></plist>'
    plistTagString = ''
    for Tag in TagList:
        plistTagString = plistTagString + '<string></string>'.format(Tag.replace("'","-"))
    TagText = plistFront + plistTagString + plistEnd

    OptionalTag = "com.apple.metadata:"
    XattrList = ["kMDItemFinderComment","_kMDItemUserTags","kMDItemOMUserTags"]
    for Field in XattrList:    
        XattrCommand = 'xattr -w 0 \'1\' "2"'.format(OptionalTag + Field,TagText.encode("utf8"),F)
        if DEBUG:
            sys.stderr.write("XATTR: \n".format(XattrCommand))
        ProcString = subprocess.check_output(XattrCommand, stderr=subprocess.STDOUT,shell=True) 
        Result += ProcString
    return Result

DEBUG = False


if __name__ == "__main__":
    if len(sys.argv) < 3:
        print __doc__
    else:
        TagList = [ sys.argv[1] ]
        # print TagList
        # Or you can hardwire your tags here
        # TagList = ['Orange','Green']
        FileList = sys.argv[2:]

        for FileName in FileList:
            writexattrs(FileName, TagList)

【讨论】:

很酷,谢谢,刚刚测试过,它似乎工作正常,并且可以通过标签从查找器中搜索文件。 +1 效果很好,但速度很慢(超过 1 秒)。 @iacopo - 如果你赶时间,使用本机 Python 库可能会更快——我只是不想有任何依赖项。您可以通过删除两个标签来加快速度,只需在_kMDItemUserTags 上执行此操作,而不是全部三个。还可以递归地一次在整个文件夹上运行xattr 命令。几乎相同的脚本,但使用xattr -rw 并给它一个文件夹名称。我认为对于一般目的,逐个文件的基础更灵活,但显然更慢。 我将脚本的第 48 行更改为 TagList = sys.argv[1].split(';'),这样如果用 ;s 分隔,就可以添加多个标签 专业提示:将tagfile.py 放入~/bin,运行chmod +x ~/bin/tagfile.py 并使用tagfile.py "SomeTag" ./some/Folder/orFile.txt 从其他文件夹运行【参考方案2】:

签出标签,“一个命令行工具,用于在 Mac OS X 10.9 Mavericks 文件上操作标签,并查询带有这些标签的文件”。 The GitHub repository has installation instructions(有 Homebrew 和 MacPorts 包)。

【讨论】:

【参考方案3】:

我添加了这个答案,因为 OP 要求提供一个 shell 脚本并将其标记为 bash。我编写了这个 Automator 服务,它用另一个文件的标签标记选定的文件。我添加了 cmets 来概述 bash 使用 bash 脚本与标签和颜色的交互。

 

基础知识

在脚本中,OpenMeta 和 Mavericks 标签都可以使用命令 xattr 访问。在没有修饰符的情况下使用它,$ xattr [file],会给出一组属性的列表。 $ xattr -h 提供了很好的使用指南。

Mavericks 的标签在 com.apple.metadata:_kMDItemUserTags 中,而 OpenMeta 标签可以在多种属性中。其中包括com.apple.metadata:kOMUserTagsorg.openmetainfo:kMDItemOMUserTagsorg.openmetainfo:kOMUserTags

Mavericks 通过将标签放置在 _kMDItemUserTags 中并将颜色放置在每个文件的 FinderInfo 中来处理不同属性中的颜色和标签。这是一个奇怪的选择,也是 Finder 在标签压力下苦苦挣扎的原因之一。如果您有 800 个标记为 kapow 的文件,每个文件位于不同的文件夹中,然后您为 kapow 选择蓝色,则 Finder 必须查找并更改每个文件的属性。

您可以通过从标记和彩色文件中删除 com.apple.FinderInfo 属性来解决这个奇怪的问题:$ xattr -d com.apple.FinderInfo [file]。颜色将在 Finder 列表中消失,但标签(及其颜色)仍与文件关联。

 

从另一个文件导入标签的 Bash 脚本

在脚本中,Finder 中选择的文件被保存到变量$tagless,选择的标签供应商是$tagfull

TAGFULID=$#@
TAGFUL=$!TAGFULID

## Use xattr to read all existing tags:
ATTRS=$(xattr "$TAGFUL")

for f in "$@" ## For every selected file in Finder, do:
do
    if("$TAGFUL"="$f") ## Is the supplier of tags is amongst the selected files?
    then
        break
    fi

    if [[ "$ATTRS" == *kMDItemUserTags* ]] ## Are there tags?
        then
        ## Load tags:
        TAGS=$(xattr -px com.apple.metadata:_kMDItemUserTags "$TAGFUL")
        ## Write tags:
        xattr -wx com.apple.metadata:_kMDItemUserTags "$TAGS" "$f"
    fi
    if [[ "$ATTRS" == *FinderInfo* ]] ## Are there colours?
    then
        ## Load colour:
        FINDERINFO=$(xattr -px com.apple.FinderInfo "$TAGFUL")
        ## Write colour:
        xattr -wx com.apple.FinderInfo "$FINDERINFO" "$f"
    fi
done

【讨论】:

【参考方案4】:

你可以试一试this:

xattr -w com.apple.metadata:_kMDItemUserTags '<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"><plist version="1.0"><array><string>Orange</string><string>Red</string></array></plist>' $currentFile

您需要将 $currentFile 替换为您要添加标签的文件,然后更改

<string>Orange</string><string>Red</string>

到您要添加的任何标签的列表。

【讨论】:

请注意,以这种方式编辑现有标签列表会很棘手,因为它通常以二进制 plist 形式存储,而不是 XML。此外,如果列表中有任何颜色标签,你真的应该设置 FinderInfo... 看来您可以使用“mdls -name kMDItemUserTags $currentFile”以更易读的方式列出以二进制格式编写的标签。 感谢@GordonDavisson 在上面的示例中,您将如何设置 FinderInfo,为什么这很重要? @nacross:我没有更好的答案,我只是指出很难做到正确。 在 el capitan 中做了我需要的事情,作为自动化脚本的一部分,用于快速标记我喜欢的照片。【参考方案5】:

在 Apple 的 What's New in OS X 中,它声明 NSURL 处理标签,Common File System Resource_Keys 提供所需的键为 NSURLTagNamesKey,并声明其值只是一个字符串数组。

【讨论】:

添加新标签就像在 URL 上设置 NSURLTagNamesKey 资源值一样简单,指定一个包含不存在的字符串(标签名称)的数组。它将立即显示在 Finder 中。【参考方案6】:

OpenMeta 框架是第三方标准,用于使用扩展属性将元数据添加到 OS X 文件。它被许多第三方应用程序使用。

或者您可以使用XATTR 命令通过命令行操作扩展属性。

【讨论】:

但这与小牛队的标签功能无关 您在这篇文章中看到 Sperr 的回答了吗? ***.com/a/19720455/393564 我没有看到 xattr 部分。有趣的。肯定有比这更好的 API。大概它会被埋在多个地方,并且可能在沙盒土地之外。 虽然 openmeta 框架确实提供了标记元数据,但它不是苹果专有标记机制的一部分。 事实上,Apple 复制了 OpenMeta 用于其标记系统,只是更改了 xattr 名称。因此,OpenMeta 在其最后的版本中只是使用 Apple 的官方 API 设置 Apple 标签。 OpenMeta 涵盖了一些“陷阱”,例如 case preserve/case insentivie 标签等。【参考方案7】:

这不包括标签,但要更改标签颜色,一种方法是通过如下命令:

xattr -wx com.apple.FinderInfo \
0000000000000000000400000000000000000000000000000000000000000000 myfile.txt

埋在中间的04正在设置文件颜色。

这是一个包装了该命令的 python 脚本,可让您在一个文件或一系列文件上设置标签颜色:

import sys
import subprocess

def colorizeFile(ColorName,FileName):
    ReverseTable = 
         "clear"  :  "01",
         "gray"   :  "03",
         "green"  :  "04",
         "purple" :  "06",
         "blue"   :  "09",
         "yellow" :  "0A",
         "red"    :  "0C",
         "orange" :  "0E",
         "c"      :  "01",
         "a"      :  "03",
         "g"      :  "04",
         "p"      :  "06",
         "b"      :  "09",
         "y"      :  "0A",
         "r"      :  "0C",
         "o"      :  "0E",
    

    HexString = 18*"0" + ReverseTable.get(ColorName) + 44*"0"
    Xcommand = 'xattr -wx com.apple.FinderInfo 0 1'.format(HexString,FileName)
    ProcString = subprocess.check_call(Xcommand, stderr=subprocess.STDOUT,shell=True) 

if __name__ == "__main__":
    if len(sys.argv)<3:
        sys.stderr.write(__doc__.format(sys.argv[0]))
    else:
        Cname = sys.argv[1]
        Flist = sys.argv[2:]
        for File in Flist:
            colorizeFile(Cname.lower(),File)
        sys.stderr.write("## Colorized 0 file(s) as 1\n".format(len(Flist),Cname)) 

用法是:

  labelcolor.py [color] *.jpg

其中 [color] 是如下定义的名称或缩写:

    clear (c), grAy (a), green (g), purple (p), 
    blue (b), yellow (y), red (r), orange (o)

【讨论】:

谢谢我试用了你的脚本,它似乎非常适合设置颜色。不幸的是,当我问这个问题时,我做出了错误的假设,即设置标签和颜色的方法将在同一个庄园中处理。我主要对设置文本标签感兴趣。 +1 虽然有用且部分答案。 由于某些原因,设置标签效果不佳。我正在使用链接答案中的方法来放置聚光灯可以搜索的关键字。我认为不仅如此,我还建议使用从命令行调用的 AppleScript 和 osascript 这也可以查看this answer。【参考方案8】:

从 Mavericks 开始,可以使用 NSURL 在 Cocoa 中获取和设置颜色标签。

NSURL 有大量可以通过setResourceValue:forKey:error:getResourceValue:forKey:error: 方法设置或读取的属性。

使用NSURLLabelNumberKey键,可以设置颜色标签,如下:

NSURL *fileURL = [NSURL fileURLWithPath:@"/Users/[username]/Documents/[some_file]"];
NSError *resourceError;
if (![fileURL setResourceValue:@(2) forKey:NSURLLabelNumberKey error:&resourceError]) 
    NSLog(@"Error while setting file resource: %@", [resourceError localizedDescription]);

如果对只有一种颜色的文件执行此操作,则会清除当前颜色并设置指定颜色。但是,如果文件上已经设置了多种颜色,则在设置指定颜色之前不会清除现有颜色。

这是值-颜色映射(在 El Capitan 上):

@(0):无 @(1):灰色 @(2):绿色 @(3): 紫色 @(4): 蓝色 @(5):黄色 @(6):红色 @(7): 橙色

我无法使用NSURLLabelColorKey 设置标签。这是我在 El Capitan 上的体验,其中的键与“标签”(颜色)相关:

NSURLLabelNumberKey:可以读取/设置成功,数字0-7。任何其他数字都将返回错误。如果设置了多个标签,那么这将返回设置的第一个颜色的索引,因为它通过索引 1 到 7 进行数字搜索。虽然您可以通过单击颜色在 Finder 中清除颜色,但以编程方式设置颜色已设置的不会清除该颜色。 NSURLLabelColorKey:即使为文件设置了颜色标签,也返回 nil。使用此键设置值无效。 NSURLTagNamesKey:返回已设置标签的颜色名称数组。

【讨论】:

如何使用此 API 设置任意标签,例如“财务”?【参考方案9】:

在问不同

有多个答案,其中一个是accepted:

Possible to tag a folder via terminal? (2013-11-15)

在 Stack Overflow 中,问题稍早出现(2013-11-01),所以我将在此处添加我的答案。

开放元

在https://code.google.com/p/openmeta/source/browse/trunk/trunk/openmeta开源

openmeta 命令似乎采用双属性方法,同时使用两者:

com.apple.metadata:kMDItemOMUserTags com.apple.metadata:_kMDItemUserTags

示例用法

sh-3.2$ sw_vers
ProductName:    Mac OS X
ProductVersion: 10.9.5
BuildVersion:   13F1096
sh-3.2$ uname -a
Darwin gpes3e-gjp4.local 13.4.0 Darwin Kernel Version 13.4.0: Wed Mar 18 16:20:14 PDT 2015; root:xnu-2422.115.14~1/RELEASE_X86_64 x86_64
sh-3.2$ date
Sun 26 Jul 2015 08:00:23 BST
sh-3.2$ rm ~/Desktop/test.txt 
sh-3.2$ touch ~/Desktop/test.txt 
sh-3.2$ xattr -l ~/Desktop/test.txt 
sh-3.2$ ./openmeta
openmeta version 0.1 by Tom Andersen code.google.com/p/openmeta/ 

Usage: openmeta [options] -p PATH[s] 

Note that commas are to be used nowhere - tag lists use quotes for two word tags in output

example (list tags and ratings):  openmeta -p PATH
example (list tags and ratings multiple):  openmeta -p PATH PATH
example (list tags): openmeta -t -p PATH[s]
example (add tags): openmeta -a foo bar -p PATH[s]
example (add tags with spaces): openmeta -a "three word tag" "foo bar" -p PATH[s]
example (set tags):  openmeta -s foo bar -p PATH[s]
example (clear all tags):  openmeta -s -p PATH[s]
example (set managed):  openmeta -m Y -p PATH[s]
example (set rating 0 - 5 stars):  openmeta -r 3.5 -p PATH[s]
example (print rating):  openmeta -r -p PATH[s]
example (clear rating):  openmeta -r 0.0 -p PATH[s]
example (lousy rating):  openmeta -r 0.1 -p PATH[s]
sh-3.2$ ./openmeta -a kerfuffle -p ~/Desktop/test.txt 
kerfuffle /Users/gjp22/Desktop/test.txt
sh-3.2$ ./openmeta -p ~/Desktop/test.txt 
/Users/gjp22/Desktop/test.txt
tags: kerfuffle
rating: none found

sh-3.2$ xattr -l ~/Desktop/test.txt 
com.apple.metadata:kMDItemOMUserTagTime:
00000000  62 70 6C 69 73 74 30 30 33 41 BB 64 BD 3C D4 95  |bplist003A.d.<..|
00000010  F2 08 00 00 00 00 00 00 01 01 00 00 00 00 00 00  |................|
00000020  00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00  |................|
00000030  00 11                                            |..|
00000032
com.apple.metadata:kMDItemOMUserTags:
00000000  62 70 6C 69 73 74 30 30 A1 01 59 6B 65 72 66 75  |bplist00..Ykerfu|
00000010  66 66 6C 65 08 0A 00 00 00 00 00 00 01 01 00 00  |ffle............|
00000020  00 00 00 00 00 02 00 00 00 00 00 00 00 00 00 00  |................|
00000030  00 00 00 00 00 14                                |......|
00000036
com.apple.metadata:_kMDItemUserTags:
00000000  62 70 6C 69 73 74 30 30 A1 01 5B 6B 65 72 66 75  |bplist00..[kerfu|
00000010  66 66 6C 65 0A 30 08 0A 00 00 00 00 00 00 01 01  |ffle.0..........|
00000020  00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 00  |................|
00000030  00 00 00 00 00 00 00 16                          |........|
00000038
kOM109SyncDone:
00000000  62 70 6C 69 73 74 30 30 09 08 00 00 00 00 00 00  |bplist00........|
00000010  01 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00  |................|
00000020  00 00 00 00 00 00 00 00 00 09                    |..........|
0000002a
sh-3.2$ 

其他实用程序的限制

例如,Apple Finder。

在使用 Finder 移除 kerfuffle 标签后,kerfuffle 仍然是 OpenMeta 标签:

sh-3.2$ date ; xattr -l ~/Desktop/test.txt 
Sun 26 Jul 2015 08:02:13 BST
com.apple.metadata:kMDItemOMUserTagTime:
00000000  62 70 6C 69 73 74 30 30 33 41 BB 64 BD 3C D4 95  |bplist003A.d.<..|
00000010  F2 08 00 00 00 00 00 00 01 01 00 00 00 00 00 00  |................|
00000020  00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00  |................|
00000030  00 11                                            |..|
00000032
com.apple.metadata:kMDItemOMUserTags:
00000000  62 70 6C 69 73 74 30 30 A1 01 59 6B 65 72 66 75  |bplist00..Ykerfu|
00000010  66 66 6C 65 08 0A 00 00 00 00 00 00 01 01 00 00  |ffle............|
00000020  00 00 00 00 00 02 00 00 00 00 00 00 00 00 00 00  |................|
00000030  00 00 00 00 00 14                                |......|
00000036
com.apple.metadata:_kMDItemUserTags:
00000000  62 70 6C 69 73 74 30 30 A0 08 00 00 00 00 00 00  |bplist00........|
00000010  01 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00  |................|
00000020  00 00 00 00 00 00 00 00 00 09                    |..........|
0000002a
kOM109SyncDone:
00000000  62 70 6C 69 73 74 30 30 09 08 00 00 00 00 00 00  |bplist00........|
00000010  01 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00  |................|
00000020  00 00 00 00 00 00 00 00 00 09                    |..........|
0000002a
sh-3.2$ 

了解这些限制

注意域和命名约定:Developer thoughts on adopting OpenMeta – Ironic Software(2009-03,现在在 Internet Archive Wayback Machine)提醒我们com.apple.metadata 是供 Apple 在 OpenMeta(一个项目不是apple.com 域中)开始了面向Apple 的com.apple.metadata:kMDItemOMUserTags 方法。

所以我不应该期望 Apple 软件获得或保持与这两种标记方法的兼容性。


边缘情况

在某些情况下,可能需要删除面向Applecom.apple.metadata:_kMDItemUserTags标签而不删除OpenMeta面向的com.apple.metadata:kMDItemOMUserTags标签。

但是,以编程方式这样做可能超出了@nacross 提出的问题的范围。

【讨论】:

以上是关于如何以编程方式将 OS X“标签”添加到文件中?的主要内容,如果未能解决你的问题,请参考以下文章

如何以编程方式将用户添加到 Oracle APEX 4.x 中的访问控制列表?

如何以编程方式将多个源添加到 HTML5 音频标签?

以编程方式将标签添加到 Swift 中的消息应用程序?

如何以编程方式修改 OS X 照片库?

以编程方式将 UILabel 和 UIImageViews 添加到 UIScrollView

如何以编程方式使 Mac OS 上的文件夹可全局写入?