Borax Mans Pad
  • About
  • Blog
  • Articles
  • Levels
  • My Computing Setup
  • Programs
  • Links

Using Extended Attributes as file tags in ZSH

There is a way with ZSH to use extended attributes on files as tags. Extended attributes are name/value pairs that can be assigned to files and directories, either using setfattr or attr commands. Most Linux POSIX filesystems support extended attributes.

This setup is allows you to use them as ’tags’, so you can do file operations only on files which have, or don’t have these tags. You can have as many tags as you like, and they’ll work on the command line.

To use them in ZSH, you’ll need the fllowing functions. Put them in your .zshrc or other zsh init file.

Firstly, you will need the following line to enable the extended attribute functions in ZSH.

zmodload zsh/attr

Then a function to match the tag you want to use.

function archived() {
	# just a check whether the archived attribute exists, regardless of value.
	local val
	zgetattr $REPLY user.archived val 2>/dev/null
}

The function above doesn’t have to be called “archived”, you can use anyname you like. Just change all occurences of the word “archived” to the tag you want. Define as many functions as you want.

I use “archived” for files which I have copied to archival disks or other media, but may want to keep around. So any file which has the “archived” attribute, I know will exist elesewhere, so I can delete it and now I’m not deleting the only copy.

It works like this.

Suppose you have a file you want to tag as “archived”. Set the tag as follows

setfattr -n user.archived filename

Then you can use ZSH glob qualifiers to select only files which have the tag.

e.g.

rm *(+archived)

This will delete files with the archived tag.

or alternatively, you may want to only operate on files not archived.

cp *(.^+archived) /media/superuser/disk/music

The above example copies all files which DON’T have the archived tag to the directory /media/superuser/disk/music

Then we can set the tag after copying

for x in *(.^+archived); do
	setfattr -n user.archived $x
done

All files which didn’t have the tag now do. We could have done this after the copy, to indicate that the files have been archived.

As I sated, you can define other functions, just change ‘archived’ to something else, like ‘obsolete’.

setfattr -n user.obsolete file_I_dont_need

Tag the file is obsolete or not really needed, but still keep it around, just because.

Now we can do a recurive delete of all files tagged obsolete

rm **/*(.+obsolete)

Or just delete in part

rm *.zip(+archived)

Delete all zips with the archived tag. Or course, you can use that in conjuction with other globbing qualifiers, to delete only those archived files modified more than one year ago, or just those over 100 megabytes or whatever.

These are just examples. Adapt these for your own circumstances and desires.

Back to Home


© Dennis Katsonis 2025

GitGud