Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/leahneukirchen/lr

list files, recursively
https://github.com/leahneukirchen/lr

Last synced: 3 months ago
JSON representation

list files, recursively

Awesome Lists containing this project

README

        

## lr: list files, recursively

`lr` is a new tool for generating file listings, which includes the
best features of `ls(1)`, `find(1)`, `stat(1)` and `du(1)`.

`lr` has been tested on Linux 4.1, FreeBSD 10.2, OpenBSD 5.7,
NetBSD 5.2.3, DragonFlyBSD 5.0, Mac OS X 10.10, OmniOS 5.11 and Cygwin 1.7.32.
It will likely work on other Unix-like systems with C99, but you'll
need to port `scan_filesystems` for `fstype` to work.

## Screenshot

![Screenshot of lr -AFGl -ovh](lr.png)

## Benefits

Over find:
* friendly and logical C-style filter syntax
* getopt is used, can mix filters and arguments in any order
* can sort
* compute directory sizes
* can strip leading `./`
* can do breadth first search

Over ls:
* sorts over all files, not per directory
* copy & paste file names from the output since they are relative to pwd
* ISO dates
* powerful filters

## Rosetta stone

* `ls`: `lr -1 | column`
* `find .`: `lr` (or `lr -U` for speed.)
* `ls -l`: `lr -1l`
* `ls -ltrc`: `lr -l1Aoc`
* `find . -name '*.c'`: `lr -t 'name ~~ "*.c"'`
* `find . -regex '.*c'`: `lr -t 'path =~ "c$"'`
* `find -L /proc/*/fd -maxdepth 1 -type f -links 0 -printf '%b %p\n'`:
`lr -UL1 -t 'type == f && links == 0' -f '%b %p\n' /proc/*/fd`
* `find "${@:-.}" -name HEAD -execdir sh -c 'git rev-parse --resolve-git-dir . >/dev/null 2>/dev/null && pwd' ';'`: `lr -0U -t 'name == "HEAD"' "$@" | xe -0 -s 'cd ${1%/*} && git rev-parse --resolve-git-dir . >/dev/null && pwd; true' 2>/dev/null`
* Filter list of files for existence: `xe lr -dQU @|`).
* `-l`: long output a la `ls -l` (implies `-Q`).
* `-TA`: with `-l`, output atime.
* `-TC`: with `-l`, output ctime.
* `-TM`: with `-l`, output mtime (default).
* `-S`: BSD stat(1)-inspired output (implies `-Q`).
* `-f FMT`: custom formatting, see below.
* `-B`: breadth first traversal.
* `-D`: depth first traversal. `prune` does not work, but `entries`
and `total` are computed on the fly.
* `-H`: only follow symlinks on command line.
* `-L`: follow all symlinks.
* `-1`: don't go below one level of directories.
* `-A`: don't list files starting with a dot.
* `-G`: colorize output to tty. Use twice to force colorize.
* `-X`: print OSC 8 hyperlinks to tty. Use twice to force.
* `-P`: quote file names using `$'...'` syntax.
* `-Q`: shell quote file names (default for output to TTY).
* `-d`: don't enter directories.
* `-h`: print human readable size for `-l` (also `%s`).
* `-s`: strip directory prefix passed on command line.
* `-x`: don't enter other filesystems.
* `-U`: don't sort results, print during traversal.
* `-W`: sort results by name and print during traversal.
* `-o ORD`: sort according to the string `ORD`, see below.
* `-e REGEX`: only show files where basename matches `REGEX`.
* `-t TEST`: only show files matching all `TEST`s, see below.

## Output formatting:

* `\a`, `\b`, `\f`, `\n`, `\r`, `\v`, `\0` as in C.
* `%%`: plain `%`.
* `%s`: file size in bytes.
* `%S`: file size, with human readable unit.
* `%b`: file size in 512-byte blocks.
* `%k`: file size in 1024-byte blocks.
* `%d`: path depth.
* `%D`: device number (`stat.st_dev`).
* `%R`: device ID for special files (`stat.st_rdev`).
* `%i`: inode number.
* `%I`: one space character for every depth level.
* `%p`: full path (`%P` if `-s`).
* `%P`: full path without command line argument prefix.
* `%l`: symlink target.
* `%n`: number of hardlinks.
* `%F`: file indicator type symbol (`*/=>@|`).
* `%f`: file basename (everything after last `/`).
* `%A-`, `%C-`, `%T-`: relative age for atime/ctime/mtime.
* `%Ax`, `%Cx`, `%Tx`: result of `strftime` for `%x` on atime/ctime/mtime.
* `%m`: octal file permissions.
* `%M`: ls-style symbolic file permissions.
* `%y`: ls-style symbolic file type (`bcdfls`).
* `%g`: group name.
* `%G`: numeric gid.
* `%u`: user name.
* `%U`: numeric uid.
* `%e`: number of entries in directories.
* `%t`: total size used by accepted files in directories (only with `-D`).
* `%Y`: type of the filesystem the file resides on.
* `%x`: Linux-only: a combination of: `#` for files with security capabilities, `+` for files with an ACL, `@` for files with other extended attributes.

## Sort order

Sort order is string consisting of the following letters.
Uppercase letters reverse sorting.
E.g. `Sn` sorts first by size, smallest last, and then by name (in
case sizes are equal).

Default: `n`.

* `a`: atime.
* `c`: ctime.
* `d`: path depth.
* `e`: file extension.
* `f`: file basename.
* `i`: inode number.
* `m`: mtime.
* `n`: file name.
* `p`: directory name.
* `s`: file size.
* `t`: file type. This sorts all directories before other files.
* `v`: file name as version numbers (sorts "2" before "10").

## Filter expressions

`lr` filters are given by the following EBNF:

::= || -- disjunction
| && -- conjunction
| ? : -- ternary operator
| ! -- negation
| (
|
|
|
|
| prune -- do not traverse into subdirectories
| print -- always true value
| skip -- always false value
| color -- always true value, override 256-color

::= atime | ctime | mtime

::= depth | dev | entries | gid | inode
| links | mode | rdev | size | total | uid

::= <= | < | >= | > | == | = | !=

::= "./path" -- mtime of relative path
| "/path" -- mtime of absolute path
| "YYYY-MM-DD HH:MM:SS"
| "YYYY-MM-DD" -- at midnight
| "HH:MM:SS" -- today
| "HH:MM" -- today
| "-[0-9]+d" -- n days ago at midnight
| "-[0-9]+h" -- n hours before now
| "-[0-9]+m" -- n minutes before now
| "-[0-9]+s" -- n seconds before now
| [0-9]+ -- absolute epoch time

::= [0-9]+ ( c -- *1
| b -- *512
| k -- *1024
| M -- *1024*1024
| G -- *1024*1024*1024
| T )? -- *1024*1024*1024*1024

::= fstype | group | name | path | target | user | xattr

::= == | = | != -- string (in)equality
| === | !=== -- case insensitive string (in)equality
| ~~ | !~~ -- glob (fnmatch)
| ~~~ | !~~~ -- case insensitive glob (fnmatch)
| =~ | !=~ | !~ -- POSIX Extended Regular Expressions
| =~~ | !=~~ -- case insensitive POSIX Extended Regular Expressions

::= " ([^"] | "")+ " -- use "" for a single " inside "
| $[A-Za-z0-9_] -- environment variable

::= type ( == | = | != ) ( b | c | d | p | f | l )

::= mode ( == | = -- exact permissions
| & -- check if all bits of set
| | -- check if any bit of set
)
| mode = "" -- check if symbolic mode is satisfied

::= [0-7]+

::= (, )+

::= [guoa]* [+-=] [rwxXstugo]* -- see chmod(1)

## EWONTFIX

The following features won't be implemented:

* `-exec`: use `-0` and `xargs`
(or even better [xe](https://github.com/leahneukirchen/xe)).
* columns: use `column`, `git-column` (supports colors), Plan 9 `mc`.
(e.g. `lr -1AGFs | git column --mode=dense --padding=2`)

## "Screenshots"

Default output, sorted by name:

```
% lr
.
.git
.git/HEAD
.git/config
[...]
Makefile
README.md
lr.c
```

Long output format:

```
% lr -l
drwxrwxr-x 3 chris users 120 2015-10-27 13:56 ./
drwxrwxr-x 7 chris users 240 2015-10-27 13:56 .git/
-rw-rw-r-- 1 chris users 23 2015-10-27 13:56 .git/HEAD
-rw-rw-r-- 1 chris users 257 2015-10-27 13:56 .git/config
[...]
-rw-rw-r-- 1 chris users 297 2015-10-27 13:56 Makefile
-rw-rw-r-- 1 chris users 5828 2015-10-27 13:56 README.md
-rw-rw-r-- 1 chris users 27589 2015-10-27 13:56 lr.c
```

Simple test:

```
% lr -F -t 'type == d'
./
.git/
.git/hooks/
.git/info/
.git/logs/
.git/logs/refs/
.git/logs/refs/heads/
.git/logs/refs/remotes/
.git/logs/refs/remotes/origin/
.git/objects/
.git/objects/info/
.git/objects/pack/
.git/refs/
.git/refs/heads/
.git/refs/remotes/
.git/refs/remotes/origin/
.git/refs/tags/
```

List regular files by size, largest first:

```
% lr -f '%S %f\n' -1 -t 'type == f' -oS
27K lr.c
5.7K README.md
297 Makefile
```

List directory total sizes, indented:

```
% lr -D -t 'type == d' -f '%I%I%t %p\n'
172 .
132 .git
40 .git/hooks
4 .git/info
12 .git/logs
8 .git/logs/refs
4 .git/logs/refs/heads
4 .git/logs/refs/remotes
4 .git/logs/refs/remotes/origin
48 .git/objects
0 .git/objects/info
48 .git/objects/pack
8 .git/refs
4 .git/refs/heads
4 .git/refs/remotes
4 .git/refs/remotes/origin
0 .git/refs/tags
```

List all files, but print them in red if they match "havoc":

```
% lr -G -t 'name =~ "havoc" && color 160 || print'
```

Do not enter `.git` or `.hg` directories:

```
% lr -t 'name = ".git" || name = ".hg" ? prune : print' .
```

## Installation

Use `make all` to build, `make install` to install relative to `PREFIX`
(`/usr/local` by default). The `DESTDIR` convention is respected.
You can also just copy the binary into your `PATH`.

## Copyright

Copyright (C) 2015-2023 Leah Neukirchen

Licensed under the terms of the MIT license, see lr.c.