On Unix-like systems, the ls command lists files. GNU's version of ls also colors them according to their properties and the environment variable LS_COLORS. The main file property that ls bases its colors on is the file's mode. In this challenge, you will determine what keys from LS_COLORS ls should look for a given mode.

File modes

A file's mode determines what type of a file it is (is it a normal file? a socket? a pipe? a directory?) and what permissions it has (can the owner execute it? can everyone write to it?).

The mode is given by a 16-bit unsigned integer. The highest 4 bits determine the file's type, the next 3 bits determine certain special attributes, and the remaining 9 bits determine user, group, and world permissions (3 bits each).

The grouping-up by 3s makes it very common write these permissions in octal:

      type  special  permissions  |      type  sp  perms
      ----  -------  -----------  |       --   --  -----
(bin) 1111    111    111 111 111  | (oct) 17    7  7 7 7

The top 4 bits will take on one of these values. Any other values can produce undefined behavior:

Binary       Octal    File type
---------    -----    ----------------
0b1100...    014...   socket
0b1010...    012...   symbolic link
0b1000...    010...   regular file
0b0110...    006...   block device
0b0100...    004...   directory
0b0010...    002...   character device
0b0001...    001...   FIFO (named pipe)

The remaining 4 octets can have any value. each bit is a flag which can be set independently from the others:

????-------------  Filetype, see above
----1------------  SUID: Execute this file with the UID set to its owner
-----1-----------  SGID: Execute this file with the GID set to its group
------1----------  Sticky: Users with write permissions to this dir cannot move or delete files within owned by others
-------1---------  User read:  The owner of the file can read this
--------1--------  User write: The owner of the file can write to this
---------1-------  User exec:  The owner of the file can execute this
-----------111---  Group r/w/x: The group of this file can read/write/execute
--------------111  Other r/w/x: All users can read/write/execute


GNU's ls uses the environment variable LS_COLORS to add color to the files it lists. The variable LS_COLORS is a colon-delimited list of key=value rules. Some of those keys are for file names (e.g.: *.tar=01;31), but we care about the file type keys.

ln      Symbolic link.
pi      Named pipe
bd      Block device
cd      Character device
or      Symbolic link pointing to a non-existent file
so      Socket
tw      Directory that is sticky and other-writable (+t,o+w)
ow      Directory that is other-writable (o+w) and not sticky
st      Directory with the sticky bit set (+t) and not other-writable
di      Directory
su      Normal file that is setuid (u+s)
sg      Normal file that is setgid (g+s)
ex      Executable normal file (i.e. has any 'x' bit set in permissions)
fi      Normal file

Now when ls finds a match in the above list, it only applies that color if that key exists in LS_COLORS. If a directory is sticky and other-writeable, but no tw key is in LS_COLORS, it will fall back to ow, then fall back to st, then fall back to di. The list above is ordered to give the same result as ls.


Take as an integer input any valid file mode, and output the fallback list of two-character codes.

Input: A file mode with a valid file type, in any convenient integer format that is at least 16 bits.

Output: The corresponding ordered list of two-character keys for a file with that mode, in fallback order. Since all codes are two characters, the concatenated string (e.g.: "twowstdi") is also acceptable, as it is still unambiguous. Additionally, printing the codes in reverse order (di st ow tw) is also fine, as long as it is consistent for all inputs.


  • Input: 17389 (in octal: 0041755)
  • Output: ["st", "di"] (the sticky bit 0001000 is set, and it is an directory 0040000.)

Test cases (these are in octal, and a symbolic equivalent for your convenience):

 Input    Symbolic      Output     | Note:
-------  ----------  ------------- | -----
0140000  s---------   so           | socket
0147777  srwsrwsrwt   so           | suid/sgid/sticky/other-writeable does not apply
0120000  l---------   ln           | symbolic link (you MAY choose to output "or" instead)
0127777  lrwsrwsrwt   ln           |
0060000  b---------   bd           | block device
0067777  brwsrwsrwt   bd           |
0020000  c---------   cd           | character device
0027777  crwsrwsrwt   cd           |
0010000  p---------   pi           | pipe
0017777  prwsrwsrwt   pi           |

0040755  drwxr-xr-x   di           | directory
0041755  drwxrwxr-t   st di        | sticky bit set
0040002  d-------w-   ow di        | other-writable
0041777  drwxrwxrwt   tw ow st di  | sticky + other-writeable
0046000  d--S--S---   di           | suid/sgid only apply to normal files

0100000  ----------   fi           | normal file
0100000  ---------T   fi           | sticky bit only applies to directories
0100100  ---x------   ex fi        | executable file
0100010  ------x---   ex fi        |
0100001  ---------x   ex fi        |
0104000  ---S------   su fi        | suid
0106777  -rwsrwsrwx   su sg ex fi  | suid has priority over sgid and executable
0102000  ------S---   sg fi        | sgid
0102777  -rwxrwsrwx   sg ex fi     | sgid has priority over executable

0110000  ?---------  <undefined>   | Unknown filetype, any output is valid

Standard loopholes are forbidden. This is , so shorter answers are best.

Similar Challenges: File Permissions, Do I have permission?


2 Answers 2


JavaScript (Node.js), 141 bytes


Try it online!

-7 bytes thanks to @Arnauld!

Takes the file mode as an integer and returns the colour string without spaces.


// Saving these values to single char variables allows the logic below to be shorter
      // Other type colors (none)
    // File colors
  // Directory colors
// The top three bits uniquely identify the mode

Charcoal, 87 bytes


Try it online! Link is to verbose version of code. Takes input in decimal and outputs without separators and in reverse order. Explanation:


Convert the input to base 2 and left-pad it to 17 bits with spaces. This ensures that it starts with a space, guaranteeing consistent behaviour of the Sum operator; other choices would have required extra bytes to arrange zero padding.


Take the first four bits, convert to decimal, and reduce modulo 8. (The alternatives was either to spend more bytes padding with zeros to allow me to convert from base 2 or to spend more bytes taking a copy of the input and integer dividing it by 4096.)


It's a socket.


It's a symbolic link.


It's a file. Filter on the file subtypes according to whether (one of) the relevant bits are set.


It's a block device.


It's a directory. Filter on the subtypes according to the combination of set bits. The base 10 conversion is safe here as the numbers 10, 11, 100, 101, 110 and 111 all end in the same three digits in both decimal and binary.


It's a character device.


It had better be a named pipe.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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