Is there a quick and simple way to tag files in bash so that a list like this one

-rw------- 1 root   88039 Sep 29 16:31 7CCE2EC3-3191-4379-C036-1C48CCCE4C6C
-rw------- 1 root 1985554 Sep 27 16:09 61C6DCDC-04C6-5137-8894-2C8930251D1E
-rw------- 1 root  248965 Sep 26 14:12 22384DC7-D60E-57CC-94C2-C5301C980990
-rw------- 1 root  293908 Sep 22 18:27 C14E6C74-C301-49CC-C625-070721CC47C1
-rw------- 1 root  120965 Sep 19 19:17 2407C1C5-D09C-41E1-9080-C2CC8C86D0CC
-rw------- 1 root   20036 Sep 13 18:32 78691D77-C4E6-4ED1-8119-C09CCC194892
-rw------- 1 root   11789 Sep 12 23:16 8C8C190C-5340-421C-96D1-D4111C5E062C
-rw------- 1 root    1884 Sep 11 22:07 CCC91959-9744-4339-9C99-0C75E301090C

becomes something like this (or similar)

-rw------- 1 root   88039 Sep 29 16:31 7CCE2EC3-3191-4379-C036-1C48CCCE4C6C
-rw------- 1 root 1985554 Sep 27 16:09 61C6DCDC-04C6-5137-8894-2C8930251D1E
-rw------- 1 root  248965 Sep 26 14:12 22384DC7-D60E-57CC-94C2-C5301C980990 -> MYOLDFILE1
-rw------- 1 root  293908 Sep 22 18:27 C14E6C74-C301-49CC-C625-070721CC47C1
-rw------- 1 root  120965 Sep 19 19:17 2407C1C5-D09C-41E1-9080-C2CC8C86D0CC -> MYNEWFILE.TXT
-rw------- 1 root   20036 Sep 13 18:32 78691D77-C4E6-4ED1-8119-C09CCC194892
-rw------- 1 root   11789 Sep 12 23:16 8C8C190C-5340-421C-96D1-D4111C5E062C -> hello.c
-rw------- 1 root    1884 Sep 11 22:07 CCC91959-9744-4339-9C99-0C75E301090C

I tried to do something with ln -s but then I end up with a lot of duplicates cause the links are in the same directory and to get a nice view I must filter ls with grep.. any help appreciated

  • Do you want attr, i.e. extended attributes? – choroba Oct 2 '17 at 16:07
  • Is this a ls output? It seems that you are using -L option (with some other to hide group or owner). Try /bin/ls -l – Paulo Oct 2 '17 at 16:25
  • yes those are outputs from an ll alias which is currently defined as ls -alF, I don't care about ownerships and / or attributes – Edoardo Oct 2 '17 at 21:14

I don't think you can reliably (mis)use any available feature to make regular ls (with or without options) do what you want. You need to redefine ls with a script, a function or an alias.

I wouldn't redefine ls itself though, at least not in this example, which is meant to be a simple proof of concept. Supporting command line switches of ls would make the example overly complex.

To implement my solution you need a filesystem supporting extended attributes and tools to manipulate them (e.g. apt-get install attr in Debian).

To set the attribute:

setfattr -n user.mytag -v "hello.c" "8C8C190C-5340-421C-96D1-D4111C5E062C"

Note: mytag is an arbitrary name. Choose one and stick to it.

To remove the attribute:

setfattr -x user.mytag "8C8C190C-5340-421C-96D1-D4111C5E062C"

You can build custom scripts or functions to do these things in a more convenient way. Now let's say you choose ll to do what you want. If it's an alias, you need to unalias it first:

unalias ll

Then define a function:

function ll() { find "$@" -maxdepth 1 -exec \
   sh -c '
      a=$(getfattr -n user.mytag --only-values "$1" 2>/dev/null)
      ls -dalF -- "$1" | tr -d "\n"
      if [ -z "$a" ]; then printf "\n"; else printf " => %s\n" "$a"; fi
   ' sh {} \;
}

Usage examples:

ll   # but see notes below
ll 8C8C190C-5340-421C-96D1-D4111C5E062C
ll /bin
ll foo.txt bar.txt

Example output:

-rw------- 1 root root 11789 Sep 12 23:16 8C8C190C-5340-421C-96D1-D4111C5E062C => hello.c

Notes:

  • I used =>, not ->, because the latter is already used by ls for symlinks.
  • POSIX requires at least one path in find invocation. Sole ll (with no arguments) may cause find to fail (compare this answer). If so, you will need some preliminary logic to pass . to find.
  • -maxdepth is not POSIX either. In case you can't use it, see this question.
  • The function simply passes all its arguments to find (as "$@"). This means this custom ll doesn't understand options normally used by ls (or common ll alias). On the other hand injecting tests into find is possible.
  • Special or unprintable characters in names or tags may cause unexpected output.
  • ls -dalF is called for every object separately, so the resulting lines may not align into regular columns. Consider -printf action instead of ls to print all the information you need, except the tag which will still require getfattr. Using tab as a separator in -printf format will columnize a multi-line output (at least to some sort). Note that with proper -printf format you won't need tr.

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.