I currently use FinderLabelMBS to read and set a folderitem Finder label. However, sometimes a file has multiple labels assigned. I'm looking for a way (with or without MBS) to read all the labels currently assigned to a folderitem. I also need to assign several labels to folderitem.
Googling around I found an Applescript to do it, but I would prefer to avoid using Applescript if possible.
Ok so I ended up going the command-line way using "xattr". It allows to display or change file extended attributes. Labels are one of the extended attributes.
I can't describe all parts in details, but I'll try to explain what I can.as once everything worked, I have not documented what each component does. But in short,
Reading the labels:
xattr -p com.apple.metadata:_kMDItemUserTags /path/to/file | xxd -r -p | plutil -convert json - -o -
In more details:
xattr -p com.apple.metadata:_kMDItemUserTags /path/to/file
xattr allows to read and manipulate extended attributes. Labels are one of them. It outputs the result as a hex dump.
- -p : Print the value associated with the attribute name
- com.apple.metadata:_kMDItemUserTags is the attribute that stores the labels
- /path/to/file : valid shell path (properly escaped)
xxd -r -p
xxd is a convert utility from hex dump to binary data
- -r : reverse convert (from hex dump to binary)
- -p : output as plain text
plutil -convert json - -o -
plutil is a utility to work with property lists and will perform the final conversion in json so it's easier to work with.
- -convert json : convert the property list to json
- - : take standard in as input
- -o : allows to specify a path for output (in our case, will be redirected)
- - : output is redirected to standard out, which will end up in the result property of the Xojo shell.
The final output is a string in json format which looks like:
Each item contains the label name followed by the color code (if there's a color). The name and color are separated by the "\n" string. The color codes are: 0=none | 1=gray | 2=green | 3=purple | 4=blue | 5=yellow | 6=red
To set the tags, rebuild the string in the same format. The same utilities are used in reverse order with some different options, but you can basically figure out the process. Any new label will still be assigned and shown, but not available in the label popup list in the finder.
xattr -xw com.apple.metadata:_kMDItemUserTags $(echo '[labelname1,labelname2,labelname3]' | plutil -convert binary1 - -o - | xxd -p -c 256 -u) /path/to/file
My needs were to replicate the labels from one file to another. I have an audio converter application and I needed the converted files to have the same labels as the originals. So I have created a small class that reads the labels, and then sets them on another file. It does not allow to manually define the labels, but it would be trivial to add.
Here's some sample code (adapted from my class but not tested)
Private Sub ReadLabels(targetFile as FolderItem) // READ FILE LABELS dim theLabels() as string dim theColors() as integer if targetFile <> nil and targetFile.Exists = true then dim s as new shell s.Execute "xattr -p com.apple.metadata:_kMDItemUserTags " + targetFile.ShellPath + " | xxd -r -p | plutil -convert json - -o -" if s.ErrorCode = 0 then dim rawResult as string = s.Result dim jsonLabels as new JSONItem(rawResult) dim lastItem as integer lastItem = jsonLabels.Count - 1 for i as integer = 0 to lastItem dim item as string item = jsonLabels.Value(i).StringValue dim parts() as string parts = item.Split(&u0A) theLabels.Append parts(0) if parts.Ubound > 0 then theColors.Append(parts(1).val) else theColors.Append(0) end if next end if end if // do your stuff with the labels and the color codes // theLabels contains an array of label names // theColors contains the matching color codes End Sub
To write the labels for a given file, create a properly formatted string as: ["hot\n1","projectX","mytag1"]
Private Sub SetLabels(targetFile as FolderItem,jsonlist as string) // WRITE FILE LABELS dim cmd as string = "xattr -xw com.apple.metadata:_kMDItemUserTags $(echo '" + _ jsonlist + "' | plutil -convert binary1 - -o - | xxd -p -c 256 -u) " + _ targetFile.ShellPath dim s as new Shell s.Execute cmd End Sub
In terminal, use "man" if you want to learn more about the different tools used:
man xattr man xxd man plutil