Apple - Possible to tag a folder via terminal?
You can use xattr. This copies the tags from file1 to file2:
xattr -wx com.apple.metadata:_kMDItemUserTags "$(xattr -px com.apple.metadata:_kMDItemUserTags file1)" file2;xattr -wx com.apple.FinderInfo "$(xattr -px com.apple.FinderInfo file1)" file2
The tags are stored in a property list as a single array of strings:
$ xattr -p com.apple.metadata:_kMDItemUserTags file3|xxd -r -p|plutil -convert xml1 - -o -
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
<string>Red
6</string>
<string>new tag</string>
<string>Orange
7</string>
<string>Yellow
5</string>
<string>Green
2</string>
<string>Blue
4</string>
<string>Purple
3</string>
<string>Gray
1</string>
</array>
</plist>
If the kColor flag in com.apple.FinderInfo is unset, Finder doesn't show the circles for colors. If the kColor flag is set to orange and the file has the red tag, Finder shows both red and orange circles. You can set the kColor flag with AppleScript:
xattr -w com.apple.metadata:_kMDItemUserTags '("Red\n6","new tag")' ~/desktop/file4;osascript -e 'on run {a}' -e 'tell app "Finder" to set label index of (POSIX file a as alias) to item 1 of {2, 1, 3, 6, 4, 5, 7}' -e end ~/desktop/file4
xattr -p com.apple.FinderInfo file|head -n1|cut -c28-29
prints the value of the bits used for the kColor flag. Red is C, orange is E, yellow is A, green is 4, blue is 8, magenta is 6, and gray is 2. The flag that would add 1 to the values is not used in OS X.
Edit: you can also use tag:
tag -l file # list
tag -a tag1 file # add
tag -s red,blue file # set
tag -r \* file # remove all tags
tag -f green # find all files with the green tag
tag -f \* # find all files with tags
tag -m red * # match (print files in * that have the red tag)
tag can be installed with brew install tag
or sudo port install tag
.
$ tag -h
tag - A tool for manipulating and querying file tags.
usage:
tag -a | --add <tags> <file>... Add tags to file
tag -r | --remove <tags> <file>... Remove tags from file
tag -s | --set <tags> <file>... Set tags on file
tag -m | --match <tags> <file>... Display files with matching tags
tag -l | --list <file>... List the tags on file
tag -f | --find <tags> Find all files with tags
<tags> is a comma-separated list of tag names; use * to match/find any tag.
additional options:
-v | --version Display version
-h | --help Display this help
-n | --name Turn on filename display in output (default)
-N | --no-name Turn off filename display in output (list)
-t | --tags Turn on tags display in output (find, match)
-T | --no-tags Turn off tags display in output (list)
-g | --garrulous Display tags each on own line (list, find, match)
-G | --no-garrulous Display tags comma-separated after filename (default)
-H | --home Find tagged files only in user home directory
-L | --local Find tagged files only in home + local filesystems (default)
-R | --network Find tagged files in home + local + network filesystems
-0 | --nul Terminate lines with NUL (\0) for use with xargs -0
It's possible to manipulate tags via pure bash commands. There's no need for a 3rd party "tag" util.
This command lists all tags of a file ($src):
xattr -px com.apple.metadata:_kMDItemUserTags "$src" | \
xxd -r -p - - | plutil -convert json -o - - | sed 's/[][]//g' | tr ',' '\n'
And here is how you can add a tag ($newtag) to a file ($src):
xattr -wx com.apple.metadata:_kMDItemUserTags \
"$(xattr -px com.apple.metadata:_kMDItemUserTags "$src" | \
xxd -r -p - - | plutil -convert json -o - - | sed 's/[][]//g' | tr ',' '\n' | \
(cat -; echo \"$newtag\") | sort -u | grep . | tr '\n' ',' | sed 's/,$//' | \
sed 's/\(.*\)/[\1]/' | plutil -convert binary1 -o - - | xxd -p - -)" "$src"
Here is a small shell script which exports a "tags" function. Usage:
tags <file>
Lists all tags of a file
tags -add <tag> <file>
Adds tag to a file
The function could be easily extend to support removing as well.
tags() {
# tags system explained: http://arstechnica.com/apple/2013/10/os-x-10-9/9/
local src=$1
local action="get"
if [[ $src == "-add" ]]; then
src=$3
local newtag=$2
local action="add"
fi
# hex -> bin -> json -> lines
local hexToLines="xxd -r -p - - | plutil -convert json -o - - | sed 's/[][]//g' | tr ',' '\n'"
# lines -> json -> bin -> hex
local linesToHex="tr '\n' ',' | echo [\$(sed 's/,$//')] | plutil -convert binary1 -o - - | xxd -p - -"
local gettags="xattr -px com.apple.metadata:_kMDItemUserTags \"$src\" 2> /dev/null | $hexToLines | sed 's/.*Property List error.*//'"
if [[ $action == "get" ]]; then
sh -c "$gettags"
else
local add="(cat -; echo \\\"$newtag\\\") | sort -u"
local write="xattr -wx com.apple.metadata:_kMDItemUserTags \"\$($gettags | $add | grep . | $linesToHex)\" \"$src\""
sh -c "$write"
fi
}
export -f tags