TMSU

$ tmsu help

Tagging

  # Use the tag command to apply tags to files

  $ tmsu tag summer.mp3 music big-jazz mp3
  New tag 'music'
  New tag 'big-jazz'
  New tag 'mp3'

  # If you have a set of files and would like to apply the same tags to each, then
  # there is an alternative form of the command that lets you put the files last

  $ tmsu tag --tags "music mp3" *.mp3

  # The 'New tag' messages let you know that you have created new tags

  $ tmsu tag spring.mp3 music mp3 folk
  $ tmsu tag winter.mp3 umsic mp3
  New tag 'umsic'

  # We can fix this with the merge command, merging the accidentally created umsic
  # tag into the existing music tag

  tmsu merge umsic music

  # We can view the tags for our newly created tagged files with the tags command

  $ tmsu tags summer.mp3
  big-jazz
  mp3
  music

  $ tmsu tags *.mp3
  spring.mp3: folk mp3 music
  summer.mp3: big-jazz mp3 music
  winter.mp3: mp3 music

Listing Files

  # Putting more than one tag lists the files that have all of the tags.

  $ tmsu files mp3
  spring.mp3
  summer.mp3
  winter.mp3

  $ tmsu files mp3 big-jazz
  summer.mp3

  $ tmsu files "mp3 and (big-jazz or folk)"
  spring.mp3
  summer.mp3
  $ tmsu files not folk
  summer.mp3
  winter.mp3

  $ tmsu files mp3 and not music
  $ tsmu files mp3 not music # The 'and' operator is implied if you omit it

Virtual File-System

  # The entries contain an ID number which ensures the filename is unique within
  # the tag directory (even when multiple files with the same name are tagged
  # with the same tag.)

  $ mkdir mp
  $ tmsu mount mp
  $ ls mp
  queries
  tags
  $ ls mp/tags
  big-jazz mp3 music
  $ ls -l mp/tags/music
  drwxr-xr-x 0 paul paul 0 2012-04-13 20:00 big-jazz
  drwxr-xr-x 0 paul paul 0 2012-04-13 20:00 mp3
  drwxr-xr-x 0 paul paul 0 2012-04-13 20:00 spring.2.mp3 -> /home/paul/spring.mp3
  drwxr-xr-x 0 paul paul 0 2012-04-13 20:00 summer.1.mp3 -> /home/paul/summer.mp3
  drwxr-xr-x 0 paul paul 0 2012-04-13 20:00 winter.3.mp3 -> /home/paul/winter.mp3
                                                   ↑
                                                file id

  # In addition to the tags view, there is also a queries directory in which you
  # can create directories containing a file query:

  $ ls mp/queries
  README.md
  $ mkdir "mp/queries/mp3 and not folk"
  $ ls "mp/queries/mp3 and not folk"
  summer.1.mp3
  winter.3.mp3
  $ ls "mp/queries/mp3 and big-jazz"
  summer.1.mp3
  $ ls mp/queries
  mp3 and big-jazz

Databases Location

  The default database is in ~/.tmsu/default.db.

  $ tmsu --database=~/music.db tag song flac
  $ export TMSU_DB=/mnt/sdcard/tmsu.db
  $ tmsu tag /mnt/sdcard/DC-143.jpg photo location:spain mountain
  $ tmsu tag /mnt/sdcard/DC-144.jpg photo location:spain chicken

Manpage

TMSU

    Commandline tool, tmsu, for applying and managing tags.
    Virtual filesystem (FUSE) for a tag-based view of your files accessible from any program.
    TMSU does not modify your files: you can stop using it and be exactly back where you started (minus your time investment).
    TMSU does not store your files: they remain at their original locations.
    Tag information is stored in a regular Sqlite3 database.
    Query files from the command line, e.g. 'music and year < 2000'.
    Add similar queries to the virtual filesystem — even from within a program's file chooser.
    Free and open-source (GPL3).


$ tmsu tag mysong.mp3 music audio year=2010
$ tmsu files music
./mysong.mp3
$ mkdir mountpoint
$ tmsu mount mountpoint
$ ls mountpoint/tags/music
mysong.1.mp3


> tmsu tag myfile.txt text work-in-progress
> tmsu tag --tags "photo wedding family" DSC-*.jpg
> mkdir mp
> tmsu mount mp
> ls mp/tags/wedding


    The program is written in Go and is licensed under GPL3.
    I'm planning a Windows port and an eventual GUI.
    I've tested on Linux only but it may work on BSD &c. (It will not work on Windows at this time.)
    tmsu does not store your files: the VFS provides symbolic links to their real locations.
    There's Zsh completion available in the 'misc' directory.
I'm abusing the file size concept a little by using it to provide a count of number of matching files for that combination of tags.

paul@annie> ll mp/tags
total 0
drwxr-xr-x 0 paul paul 1 2012-02-06 03:00 square
drwxr-xr-x 0 paul paul 2 2012-02-06 03:00 red
drwxr-xr-x 0 paul paul 1 2012-02-06 03:00 hairy


What happens when you move a file?

The files are stored by path, so moving a file will disassociate it with its tags. BUT I also store a sha256 fingerprint for every file, so I have the groundwork to recognize a duplicate file such that it can be reassociated with its tags.

For example, with the current build, tmsu will notify you if you tag a duplicate file but will not offer any way of copying tags across automatically:

> echo hello > a.txt
> cp a.txt b.txt
> tmsu tag a.txt red square
New tag 'red'.
New tag 'square'.
> tmsu tag b.txt red
File is a duplicate of previously tagged files.
    /home/paul/a.txt

There's also a dupes command that can be used to 1. find duplicates in the database or 2. find out if a file is a duplicate before you bother to tag it.

I plan on expanding the 'dupes' command to allow tags to be copied between dupes. Either that or make it fully automatic, i.e. a duplicate file inherit tags for its fingerprint. I was even considering adding an 'add' command to add files without tagging and thought this command could apply any tags that match the file's fingerprint -- a move operation would simply be a case of adding the new file at its new location and clearing out the broken reference. (Originally I was going to associate tags to fingerprints but realized this would disassociate a file with its tags if you edit it!)

Also the status command reports the status of files when you move stuff about: missing files are show prefixed with an exclamation mark, tagged files with 'T' and untagged files with '?', much like a repository.


Hmm if the file contents change then the hash will be incorrect right? To me it feels like you could do something with a files inode instead of its path, but I don't know much about file systems :/ I really like the idea though!

Yes, if the contents change the hash will be incorrect but it gets updated automatically if you add a new tag. At the moment the dupes detection works a lot better for static content than dynamic. Inodes would not work as two files with the same contents would have two different inodes.

How about basing your database around the filename AND the inode - then using inotify or somesuch to automagically update the symbolic links and hash when a file is moved/renamed or its contents change?

    Inodes would not work as two files with the same contents would have two different inodes.

I'm not sure what you mean here - shouldn't two (separate) files - even though they have the same contents - be able to be tagged differently?

That could work, it would be an interesting experiment. My concerns are:

    tmsu would have to be running as as service in order to listen to these changes. If changes happened when tmsu was not running then a reconcilliation task would have to be run manually. I guess this is no worse than the current situation but I'd rather not have the magic unless I can guarantee it would work.
    The approach relies upon the existence of inodes. Some file systems, even on Linux (e.g. ReiserFS), do not have an inode table (although they may have something similar). It certainly wouldn't work cross-platform unless there is some parallel to the inode on other platforms. Can we be sure that a file's inode number does not change over time for all file system types?
    I assume inodes are only unique within a single file system so what I store will have to have to include an identifier for the target file system in question otherwise tmsu could get confused when the same inode number arises on two different file systems.

If I can find an inode substitute across file-systems and platforms then storing these would make it very easy to track the renaming/movement of files, but only within the same file system.

For the most part I would expect tagging to be applied to largely static documents, e.g. photograph libraries, music libraries, &c. so I don't want to affect simplicity too much for the sake of tracking modified files.

    shouldn't two separate files [...] be able to be tagged differently.

Yes, I think ultimately the decision about how to treat files with identical contents should be up to the user, but from my own experiences when I have two files with the same contents it's usually in error: I've backed up the same file multiple times to different locations or I've ripped the same CD multiple times, &c. In fact the only case I can think of where you would want to not treat the duplicate as erroneous is when one has just started work on a document and has a file with very little contents, e.g. if I were writing two different letters and had put 'Dear Sir/Madam' in both of them. So I want to make it very easy for a user to copy tags between files that have been identified as duplicates.

Can you tag a folder?

Yes, you can tag folders no prob. It will tag the folder itself though, not the files inside.

Duplicate detection is turned off for folders: I haven't thought about how to detect duplicate folders yet. I guess I'll provably make a fingerprint of the folder contents fingerprints.
TMSU does not interfere with your existing file system structure and neither does it alter your files in any way.

The taggings you choose to apply are stored separately in the TMSU database. You can then use the command line tooling to query this database, or mount a virtual file system which reflects the taggings you apply. This virtual file system provides symbolic links back to wherever you files actually live. Torrents are not going to be affected because the files are identical before and after tagging.

So TMSU is orthogonal to your existing file system: it's an alternative tag based view presented within the confines of the Unix tree file system. It's a compromise, no question: but I think it's the best we can do without reinventing the file system which we obviously can't easily do because it will break every application.

For a file DCIM1.jpg tagged 'year:2012' and 'good' and a file DCIM2.jpg tagged 'year:2012', the directory structure is laid out like this:

─O mountpoint
 └─O tags
   ├─Ⓣ year:2012
   │ ├─Ⓣ good
   │ │ └─Ⓕ DCIM1.4.jpg -> /user/home/bob/photos/DCIM1.jpg
   │ ├─Ⓕ DCIM1.4.jpg -> /user/home/bob/photos/DCIM1.jpg
   │ └─Ⓕ DCIM2.7.jpg -> /user/home/bob/photes/DCIM2.jpg
   └─Ⓣ good
     ├─Ⓣ year:2012
     │ └─Ⓕ DCIM1.4.jpg -> /user/home/bob/photos/DCIM1.jpg
     └─Ⓕ DCIM1.4.jpg -> /user/home/bob/photos/DCIM1.jpg
     Can you tag tags in TMSU? For example, if I have tags "mp3" and "music", I may want to tag "mp3" as "music", then it could be accessed as "music/mp3" in the vfs.

     Currently you can. TMSU will not notice that a path is a VFS path and so you could actually tag the VFS tag directory. However my plan is to change this at some point such that acting upon the VFS actually acts upon the target files instead.

Having said that I also have plans for tag implications. This feature would let you specify that certain tags imply others so you could say "when I tag 'mp3' I implicitly also mean 'music'.

Even in the current version, if you tag your files 'mp3' and 'music' you can get at just the MP3s via mountpoint/tags/mp3 and also mountpoint/tags/music/MP3 where the latter means 'music AND mp3', but the two will be synonymous if music is a superset

I have the exact same problem: organizing a huge number of papers I've collected in the course of my PhD.

I wrote a program specifically to manage them, which used tags and looks somewhat like TMSU (which I just learned about a few minutes ago). I never released the source, because it never really worked that well.

Specifically, I didn't have a good method for tagging things. There were too many tags that overlapped with too many other tags. So adding a new paper required adding the correct, say, 11 tags.

To help with this, I created a system to easily specify certain rules that would be enforced. For example, if tag X is added, then tag Y or Z (but not both) must also be present on the same item.

However, it was still too much of a pain.
TMSU

  config    Views or amends database settings
  copy      Create a copy of a tag
  delete    Delete one or more tags
  dupes     Identify duplicate files
  files     List files with particular tags
  help      List subcommands or show help for a particular subcommand
  imply     Creates a tag implication
  info      Show database information
  init      Initializes a new database
  merge     Merge tags
  rename    Rename a tag or value
  repair    Repair the database
  status    List the file tagging status
  tag       Apply tags to files
  tags      List tags
  untag     Remove tags from files
  untagged  List untagged files
  values    List values

Global options:

  -v --verbose   show verbose messages
  -h --help      show help and exit
  -V --version   show version information and exit
  -D --database  use the specified database
     --color     colorize the output (auto/always/never)

tmsu config
tmsu config NAME[=VALUE]...

  Lists or views the database settings for the current database.

  Without arguments the complete set of settings are shown, otherwise lists the settings for the specified setting NAMEs.

  If a VALUE is specified then the setting is updated.

tmsu copy TAG NEW...

  Creates a new tag NEW applied to the same set of files as TAG.

  Examples:

    $ tmsu copy cheese wine
    $ tmsu copy report document text

  Aliases: cp

tmsu delete TAG...

  Permanently deletes the TAGs specified.

  Examples:

    $ tmsu delete pineapple
    $ tmsu delete red green blue

  Aliases: del rm

  Options:

       --value  delete a value

tmsu dupes [FILE]...

  Identifies all files in the database that are exact duplicates of FILE. If no FILE is specified then identifies duplicates between files in the database.

  Examples:

    $ tmsu dupes
    Set of 2 duplicates:
      /tmp/song.mp3
      /tmp/copy of song.mp3a
    $ tmsu dupes /tmp/song.mp3
    /tmp/copy of song.mp3

  Options:

    -r --recursive  recursively check directory contents

tmsu files [OPTION]... [QUERY]

  Lists the files in the database that match the QUERY specified. If no query is specified, all files in the database are listed.

  QUERY may contain tag names to match, operators and parentheses. Operators are: and or not == != < > <= >= eq ne lt gt le ge.

  Queries are run against the database so the results may not reflect the current state of the filesystem. Only tagged files are matched: to identify untagged files use the untagged subcommand.

  Note: If your tag or value name contains whitespace, operators (e.g. <) or parentheses (( or )), these must be escaped with a backslash \, e.g. \<tag\> matches the tag name <tag>. Your shell, however, may use
  some punctuation for its own purposes: this can normally be avoided by enclosing the query in single quotation marks or by escaping the problem characters with a backslash.

  Examples:

    $ tmsu files music mp3 # files with both 'music' and 'mp3'
    $ tmsu files music and mp3 # same query but with explicit 'and'
    $ tmsu files music and not mp3
    $ tmsu files "music and (mp3 or flac)"
    $ tmsu files "year == 2016"
    $ tmsu files "year < 2016"
    $ tmsu files year lt 2016
    $ tmsu files year
    $ tmsu files --path=/home/bob music
    $ tmsu files 'contains\=equals'
    $ tmsu files '\<tag\>'

  Aliases: query

  Options:

    -d --directory    list only items that are directories
    -f --file         list only items that are files
    -0 --print0       delimit files with a NUL character rather than newline.
    -c --count        lists the number of files rather than their names
    -p --path         list only items under PATH
    -e --explicit     list only explicitly tagged files
    -s --sort         sort output: id, none, name, size, time
    -i --ignore-case  ignore the case of tag and value names

tmsu help [OPTION]... [SUBCOMMAND]

  Shows help summary or, where SUBCOMMAND is specified, help for SUBCOMMAND.

  Options:

    -l --list  list commands

tmsu imply [OPTION] TAG[=VALUE] IMPL[=VALUE]...
tmsu imply

  Creates a tag implication such that any file tagged TAG will be implicitly tagged IMPL.

  When run without arguments lists the set of tag implications.

  Tag implications are applied at time of file query (not at time of tag application) therefore any changes to the implication rules will affect all further queries.

  By default the tag subcommand will not explicitly apply tags that are already implied by the implication rules.

  The tags subcommand can be used to identify which tags applied to a file are implied.

  Examples:

    $ tmsu imply mp3 music
    $ tmsu imply
    mp3 -> music
    $ tmsu imply aubergine aka=eggplant
    $ tmsu imply --delete mp3 music

  Options:

    -d --delete  deletes the tag implication

tmsu info

  Shows the database information.

  Aliases: stats

  Options:

    -s --stats  show statistics
    -u --usage  show tag usage breakdown

tmsu init [PATH]

  Initializes a new local database.

  Creates a .tmsu directory under PATH and initialises a new empty database within it.

  If no PATH is specified then the current working directory is assumed.

  The new database is used automatically whenever TMSU is invoked from a directory under PATH (unless overriden by the global --database option or the TMSU_DB environment variable.

tmsu merge TAG... DEST

  Merges TAGs into tag DEST resulting in a single tag of name DEST.

  Examples:

    $ tmsu merge cehese cheese
    $ tmsu merge outdoors outdoor outside

  Options:

       --value  merge values

tmsu rename [OPTION]... OLD NEW

  Renames a tag or value from OLD to NEW.

  Attempting to rename a tag or value with a name that already exists will result in an error. To merge tags or values use the merge subcommand instead.

  Examples:

    $ tmsu rename montain mountain
    $ tmsu rename --value MMXV 2016

  Aliases: mv

  Options:

       --value  rename a value

tmsu repair [OPTION]... [PATH]...
tmsu repair [OPTION]... repair --manual OLD NEW

  Fixes broken paths and stale fingerprints in the database caused by file modifications and moves.

  Modified files are identified by a change to the file's modification time or file size. These files are repaired by updating the details in the database.

  An attempt is made to find missing files under PATHs specified. If a file with the same fingerprint is found then the database is updated with the new file's details. If no PATHs are specified, or no match can
  be found, then the file is instead reported as missing.

  Files that have been both moved and modified cannot be repaired and must be manually relocated.

  When run with the --manual option, any paths that begin with OLD are updated to begin with NEW. Any affected files' fingerprints are updated providing the file exists at the new location. No further repairs are
  attempted in this mode.

  Examples:

    $ tmsu repair
    $ tmsu repair /new/path # look for missing files here
    $ tmsu repair --path=/home/sally # repair subset of database
    $ tmsu repair --manual /home/bob /home/fred # manually repair paths

  Aliases: fix

  Options:

    -p --path         limit repair to files in database under path
    -P --pretend      do not make any changes
    -R --remove       remove missing files from the database
    -m --manual       manually relocate files
    -u --unmodified   recalculate fingerprints for unmodified files
       --rationalize  remove explicit taggings where an implicit tagging exist

tmsu status [PATH]...

  Shows the status of PATHs.

  Where PATHs are not specified the status of the database is shown.

    T - Tagged
    M - Modified
    ! - Missing
    U - Untagged

  Status codes of T, M and ! mean that the file has been tagged (and thus is in the TMSU database). Modified files are those with a different modification time or size to that in the database. Missing files are
  those in the database but that no longer exist in the file-system.

  Note: The repair subcommand can be used to fix problems caused by files that have been modified or moved on disk.

  Examples:

    $ tmsu status
    $ tmsu status .
    $ tmsu status --directory *

  Options:

    -d --directory       do not examine directory contents (non-recursive)
    -P --no-dereference  do not follow symbolic links

tmsu tag [OPTION]... FILE TAG[=VALUE]...
tmsu tag [OPTION]... --tags="TAG[=VALUE]..." FILE...
tmsu tag [OPTION]... --from=SOURCE FILE...
tmsu tag [OPTION]... --create {TAG|=VALUE}...
tmsu tag [OPTION[... -

  Tags the file FILE with the TAGs and VALUEs specified.

  Optionally tags applied to files may be attributed with a VALUE using the TAG=VALUE syntax.

  Tag and value names may consist of one or more letter, number, punctuation and symbol characters (from the corresponding Unicode categories). Tag names cannot contain the slash / or backslash \ characters.

  Tags will not be applied if they are already implied by tag implications. This behaviour can be overriden with the --explicit option. See the imply subcommand for more information.

  If a single argument of - is passed, TMSU will read lines from standard input in the format 'FILE TAG[=VALUE]...'.

  Note: The equals = and whitespace characters must be escaped with a backslash \ when used within a tag or value name. However, your shell may use the backslash for its own purposes: this can normally be avoided
  by enclosing the argument in single quotation marks or by escaping the backslash with an additional backslash \\.

  Examples:

    $ tmsu tag mountain1.jpg photo landscape holiday good country=france
    $ tmsu tag --from=mountain1.jpg mountain2.jpg
    $ tmsu tag --tags="landscape" field1.jpg field2.jpg
    $ tmsu tag --create bad rubbish awful =2016
    $ tmsu tag sheep.jpg 'contains\=equals'
    $ tmsu tag sheep.jpg '<tag>'

  Options:

    -t --tags            the set of tags to apply
    -r --recursive       recursively apply tags to directory contents
    -f --from            copy tags from the SOURCE file
    -c --create          create tags or values without tagging any files
    -e --explicit        explicitly apply tags even if they are already implied
    -F --force           apply tags to non-existant or non-permissioned paths
    -P --no-dereference  do not follow symbolic links (tag the link itself)

tmsu tags [OPTION]... [FILE]...

  Lists the tags applied to FILEs. If no FILE is specified then all tags in the database are listed.

  When color is turned on, tags are shown in the following colors:

    Normal An explicitly applied (regular) tag
    Cyan   Tag implied by other tags
    Yellow Tag is both explicitly applied and implied by other tags

  See the imply subcommand for more information on implied tags.

  Examples:

    $ tmsu tags
    mp3 music opera
    $ tmsu tags tralala.mp3
    mp3 music opera
    $ tmsu tags tralala.mp3 boom.mp3
    ./tralala.mp3: mp3 music opera
    ./boom.mp3: mp3 music drum-n-bass
    $ tmsu tags --count tralala.mp3

  Options:

    -c --count           lists the number of tags rather than their names
    -1                   list one tag per line
    -e --explicit        do not show implied tags
    -n --name            always print the file name
    -P --no-dereference  do not follow symlinks (show tags for symlink itself)

tmsu untag [OPTION]... FILE TAG[=VALUE]...
tmsu untag [OPTION]... --all FILE...
tmsu untag [OPTION]... --tags="TAG[=VALUE]..." FILE...

  Disassociates FILE with the TAGs specified.

  Examples:

    $ tmsu untag mountain.jpg hill county=germany
    $ tmsu untag --all mountain-copy.jpg
    $ tmsu untag --tags="river underwater year=2016" forest.jpg desert.jpg

  Options:

    -a --all             strip each file of all tags
    -t --tags            the set of tags to remove
    -r --recursive       recursively remove tags from directory contents
    -P --no-dereference  do not follow symbolic links (untag the link itself)

tmsu untagged [OPTION]... [PATH]...

  Identify untagged files in the filesystem.

  Where PATHs are not specified, untagged items under the current working directory are shown.

  Examples:

    $ tmsu untagged
    $ tmsu untagged /home/fred/drawings

  Options:

    -d --directory       do not examine directory contents (non-recursive)
    -c --count           list the number of files rather than their names
    -P --no-dereference  do not dereference symbolic links

tmsu values [OPTION]... [TAG]...

  Lists the values for TAGs. If no TAG is specified then all tags are listed.

  Examples:

    $ tmsu values year
    2000
    2001
    2016
    $ tmsu values
    2000
    2001
    2016
    cheese
    opera
    $ tmsu values --count year
    3

  Options:

    -c --count  lists the number of values rather than their names
    -1          list one value per line