macos - ¿Cómo puedo agregar "etiquetas" de OS X a los archivos mediante programación?
cocoa metadata (10)
Desde Mavericks, OS X ha tenido la capacidad de etiquetar y colorear archivos en el Finder.
¿Hay alguna forma de agregar etiquetas a los archivos a través de las API de Cocoa o mediante un comando de shell?
En preguntar diferente
Con respuestas múltiples, una de las cuales es accepted :
- Posible etiquetar una carpeta a través de terminal? (2013-11-15)
Aquí en , la pregunta surgió un poco antes (2013-11-01), así que agregaré mi respuesta aquí.
openmeta
Código abierto en https://code.google.com/p/openmeta/source/browse/trunk/trunk/openmeta
El comando openmeta
parece tener un enfoque de doble atributo, trabajando con ambos:
-
com.apple.metadata:kMDItemOMUserTags
-
com.apple.metadata:_kMDItemUserTags
Ejemplo de uso
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$
Limitaciones de otras utilidades.
Apple Finder, por ejemplo.
Después de usar el Finder para eliminar la etiqueta kerfuffle , kerfuffle permanece como una etiqueta 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$
Entendiendo esas limitaciones
Con atención a los dominios y las convenciones de nomenclatura: los pensamientos de los desarrolladores sobre la adopción de OpenMeta - Ironic Software (2009-03, y ahora en Internet Archive Wayback Machine) nos recuerdan que com.apple.metadata
era para el uso de Apple cuando OpenMeta (un proyecto que no está en el dominio apple.com
) comenzó el enfoque com.apple.metadata:kMDItemOMUserTags
orientado a Apple.
Por lo tanto, no debería esperar que el software de Apple obtenga o mantenga la compatibilidad con ambos enfoques de etiquetado.
Casos de borde
En algunos casos, puede ser conveniente eliminar las etiquetas de Apple orientadas a com.apple.metadata:_kMDItemUserTags
sin eliminar las etiquetas de OpenMeta orientadas a com.apple.metadata:kMDItemOMUserTags
.
Sin embargo, hacerlo de manera programática probablemente esté fuera del alcance de la pregunta formulada por @nacross.
Agrego esta respuesta, porque OP pidió un script de shell y lo etiquetó bash . Escribí este servicio de Automator, que etiqueta el archivo seleccionado con las etiquetas de otro archivo. He añadido comentarios para describir el uso de la interacción de bash con las etiquetas y los colores utilizando el script de bash.
Lo esencial
En los scripts, se puede acceder a las etiquetas de OpenMeta y Mavericks con el comando xattr . Usándolo sin modificadores, $ xattr [file]
, proporciona una lista de atributos establecidos. $ xattr -h
da una buena guía de uso.
Las etiquetas de Mavericks están en com.apple.metadata: _kMDItemUserTags, mientras que las etiquetas de OpenMeta pueden estar en una variedad de atributos. Entre otros com.apple.metadata:kOMUserTags
, org.openmetainfo:kMDItemOMUserTags
y org.openmetainfo:kOMUserTags
.
Mavericks maneja los colores y las etiquetas en diferentes atributos, colocando etiquetas en _kMDItemUserTags y colores en FinderInfo para cada archivo. Esta es una elección extraña, y es una de las razones por las que Finder tiene problemas bajo la presión de etiquetar. Si tiene 800 archivos etiquetados como kapow , cada uno en una carpeta diferente, y posteriormente elige el color azul para kapow , Finder tiene que encontrar y modificar los atributos de cada archivo.
Puede jugar con la rareza eliminando el atributo com.apple.FinderInfo de un archivo etiquetado y coloreado: $ xattr -d com.apple.FinderInfo [file]
. El color desaparecerá en las listas del Finder, pero la etiqueta (y su color) permanecerán asociadas al archivo.
Bash script para importar etiquetas de otro archivo
En el script, los archivos seleccionados en Finder se guardan en la variable $ tagless , y el proveedor elegido de etiquetas es $ 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
En Novedades de Apple en OS X, se establece que NSURL
maneja las etiquetas, y las NSURL
recursos comunes del sistema de archivos proporciona la clave requerida como NSURLTagNamesKey
y establece que su valor es solo una matriz de cadenas.
Esto no cubre las etiquetas, pero para cambiar los colores de las etiquetas, una forma de hacerlo es a través de un comando como este:
xattr -wx com.apple.FinderInfo /
0000000000000000000400000000000000000000000000000000000000000000 myfile.txt
El 04
enterrado en el medio está configurando el color del archivo.
Aquí hay una secuencia de comandos de Python que envuelve ese comando que le permite establecer el color de la etiqueta en un archivo o serie de archivos:
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))
El uso es:
labelcolor.py [color] *.jpg
donde [color] es un nombre o abreviatura como se define a continuación:
clear (c), grAy (a), green (g), purple (p),
blue (b), yellow (y), red (r), orange (o)
Lo siento por agregar otra respuesta, pero la relacionada con la configuración de los colores de la etiqueta ya era bastante larga. Aquí hay un extracto de un script de python que utilizo para establecer las etiquetas de usuario. Parece funcionar para hacer que las cosas se puedan buscar, pero no estoy seguro de si las etiquetas se mostrarán correctamente. El uso es básicamente:
tagfile.py "Tag Name" FileOrFolderName
Código abajo.
#! /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)
Podrías darle una oportunidad a esto:
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
Querrá reemplazar $ currentFile con el archivo al que desea agregar etiquetas y cambiar
<string>Orange</string><string>Red</string>
a una lista de las etiquetas que desee agregar.
Revise la etiqueta, "una herramienta de línea de comandos para manipular las etiquetas en los archivos Mavericks de Mac OS X 10.9, y consultar archivos con esas etiquetas". El repositorio de GitHub tiene instrucciones de instalación (hay paquetes Homebrew y MacPorts).
A partir de Mavericks, es posible obtener y establecer etiquetas de color en Cocoa, utilizando NSURL
.
NSURL
tiene una gran cantidad de propiedades que se pueden establecer o leer, a través de los respectivos setResourceValue:forKey:error:
y getResourceValue:forKey:error:
Usando la clave NSURLLabelNumberKey
, puede establecer las etiquetas de color de la siguiente manera:
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]);
}
Si esto se ejecuta en un archivo que solo tiene un color, borra el color actual y establece el color especificado. Sin embargo, si ya hay varios colores establecidos en el archivo, entonces no borra los colores existentes antes de configurar el color especificado.
Aquí está el mapeo valor-color (en El Capitán):
- @ (0): Ninguno
- @ (1): Gris
- @ (2): Verde
- @ (3): Púrpura
- @ (4): Azul
- @ (5): Amarillo
- @ (6): Rojo
- @ (7): Naranja
No he podido establecer una etiqueta utilizando NSURLLabelColorKey
. Aquí está mi experiencia en El Capitán, con las claves relacionadas con ''etiquetas'' (Colores):
-
NSURLLabelNumberKey
: se puede leer / configurar con éxito, con los números 0-7. Cualquier otro número devolverá un error. Si hay varias etiquetas establecidas, esto devolverá el índice del primer color establecido, ya que busca numéricamente a través de los índices 1 a 7. Aunque puede borrar un color en el Finder haciendo clic en el color, programando un color que ya está establecido no borra ese color. -
NSURLLabelColorKey
: devuelve nil, incluso cuando se establece una etiqueta de color para un archivo. Establecer un valor con esta tecla no tiene efecto. -
NSURLTagNamesKey
: devuelve una matriz de los nombres de color para las etiquetas que se establecen.
A partir de Mavericks, también es posible establecer etiquetas de colores en Cocoa, utilizando NSAppleScript
.
NSURL *fileURL = [NSURL fileURLWithPath:@"/Users/sheaparis/Documents/filezilla_sites.xml"];
//Format the filepath for the AppleScript environment.
// Without this, the file cannot be found.
NSString *filepath = [fileURL path];
NSString *appleScriptFilePath = [filepath stringByReplacingOccurrencesOfString:@"/" withString:@":"];
if ([appleScriptFilePath hasPrefix:@":"]) {
appleScriptFilePath = [appleScriptFilePath substringFromIndex:1];
}
NSLog(@"appleScriptFilePath: %@", appleScriptFilePath);
//Tells Finder to set the Red color tag for the specified file
NSString *sourceString = [NSString stringWithFormat:
@"set theFile to /"%@/" as alias/n"
"tell application /"Finder/" to set label index of theFile to 2", appleScriptFilePath];
NSAppleScript *script = [[NSAppleScript alloc] initWithSource:sourceString];
NSDictionary *scriptErrorDict = nil;
[script executeAndReturnError:&scriptErrorDict];
if (scriptErrorDict) {
NSLog(@"errorDict: %@", scriptErrorDict);
}
Si esto se ejecuta en un archivo que solo tiene un color, borra el color actual y establece el color especificado. Sin embargo, si ya hay varios colores establecidos en el archivo, entonces no borra los colores existentes antes de configurar el color especificado.
Usando el entorno AppleScript
, la asignación de colores es la siguiente:
- 0: ninguno
- 1: naranja
- 2: rojo
- 3: amarillo
- 4: azul
- 5: púrpura
- 6: verde
- 7: gris