Read Linux File Attributes Safely with lsattr

Permissions are not the whole story on an ext filesystem, and lsattr reads what ls -l cannot show. It surfaces bits like immutable or append-only that quietly change how a file behaves. This guide covers a single file, hidden entries, directories versus their contents, recursive output, long names, and the project and generation numbers people forget exist. Ten minutes, a shell, and the e2fsprogs package; everything here is read-only and normally needs no elevated privileges.

1. Check the installed command

This machine has lsattr from e2fsprogs 1.47.0-2.4~exp1ubuntu4.1, and the utility itself reports version 1.47.0, dated 5 February 2023. Your distribution may package something different, so check before trusting output details in a script:

$ command -v lsattr
/usr/bin/lsattr
$ lsattr -V
lsattr 1.47.0 (5-Feb-2023)

The documented syntax is lsattr [-RVadlpv] [files...]. There is no GNU-style --help on this build; read man lsattr instead.

2. Inspect one file

$ lsattr /path/to/file
--------------e------- /path/to/file

That string is a fixed set of character positions: a letter means the attribute is set, a hyphen means it is not, and which letters are possible depends on your filesystem and kernel. The e above just means the file uses extents, which is normal on ext4. Do not recite the attribute letters from memory when a security or recovery decision rides on them; man chattr documents what each one means, since lsattr only reads them.

Checkpoint: a successful run just prints the path back at you. It has read metadata, nothing more; it cannot set, clear or repair an attribute.

3. A directory's attributes, not its contents' attributes

Without an option, a directory is treated as a container and its entries get listed. Use -d to treat the directory inode itself like an ordinary file:

$ lsattr -d /path/to/directory
--------------e------- /path/to/directory

This is a genuinely common source of wrong conclusions: seeing attributes on files inside a directory tells you nothing about the directory's own inode. And -d never recurses, it only ever reports the one entry:

$ lsattr /path/to/directory
--------------e------- /path/to/directory/file-a
--------------e------- /path/to/directory/file-b
$ lsattr -d /path/to/directory
--------------e------- /path/to/directory

4. Include hidden entries when auditing

-a includes names starting with a dot, plus the conventional . and .. entries:

$ lsattr -a /path/to/directory
--------------e------- /path/to/directory/.
--------------e------- /path/to/directory/file-a
--------------e------- /path/to/directory/.hidden
-----------I--e------- /path/to/directory/..

Order and exact attributes will vary; the point is that hidden names show up at all. A shell glob like /path/to/directory/* is not a substitute, since it normally skips dotfiles entirely.

5. Use long names when the letters get confusing

The compact string scans fast but reads badly to someone else. -l spells it out:

$ lsattr -l /path/to/file
/path/to/file Extents

Easier to hand to a colleague, harder to parse in a script. Pick one form for automation and test it against the exact e2fsprogs version you deploy; do not mix the readable form into a parser built for compact positions.

6. Project and generation numbers

-p shows the project number, -v the version or generation number, both separate from the attribute letters themselves:

$ lsattr -pv /path/to/file
    0 2407015937 --------------e------- /path/to/file

These are filesystem metadata, not timestamps and not any kind of backup history. Zero or an unfamiliar value can simply mean the field is unset or unsupported on this filesystem. Record the full line if you are comparing before and after maintenance work.

7. Traverse a tree, carefully

-R recurses, printing a directory heading before each subdirectory's contents:

$ lsattr -R /path/to/tree
--------------e------- /path/to/tree/file-a

/path/to/tree/subdirectory:
--------------e------- /path/to/tree/subdirectory/file-b

This can produce a lot of output fast, and may hit directories you cannot read. If you redirect it to a report, check the destination name first: > truncates an existing file before lsattr even starts.

$ lsattr -R /path/to/tree > attributes.txt
$ test -s attributes.txt && echo 'attribute report created'

Warning: if an old report matters, use a fresh filename such as attributes-$(date +%Y%m%d).txt, or copy it first. lsattr itself changes no filesystem attributes, but careless redirection can destroy a report you needed. Deleting an unwanted one afterwards is a separate, irreversible step that has nothing to do with lsattr.

Common traps

Command errors on a path? Check existence and readability first, do not jump straight to sudo:

$ ls -ld /path/to/file
$ test -r /path/to/file && echo readable
$ lsattr /path/to/file

Done means