leah blogs

July 2013

04jul2013 · Summer of Scripts: l and lr

As you can guess by their names, l and lr are tools I use frequently. l was there first and simply lists all files recursively that possibly match a given pattern.

l() {
  local p=$argv[-1]
  [[ -d $p ]] && { argv[-1]=(); } || p='.'
  find $p ! -type d | sed 's:^./::' | egrep "${@:-.}"
}

It’s nice to naviate large codebases:

src/emacs-24.3% l term.c
etc/e/eterm-color
etc/e/eterm-color.ti
src/term.c
src/w32term.c
src/xterm.c
lisp/term/common-win.elc
lisp/term/cygwin.elc
lisp/term/cygwin.el
lisp/term/common-win.el

Note that it uses extended regular expressions instead of globs.

Also, you can pass a directory as the last argument to search there:

% l utmp /usr/share/man  
/usr/share/man/man8/systemd-update-utmp-runlevel.service.8.gz
/usr/share/man/man8/systemd-update-utmp.service.8.gz
/usr/share/man/man8/utmpset.8.gz
/usr/share/man/man8/systemd-update-utmp.8.gz
/usr/share/man/man0/utmpx.h.0p.gz
/usr/share/man/man5/utmp.5.gz
/usr/share/man/man5/utmpx.5.gz
/usr/share/man/man1/utmpdump.1.gz
/usr/share/man/man3/utmpxname.3.gz
/usr/share/man/man3/utmpname.3.gz
/usr/share/man/man3/getutmpx.3.gz
/usr/share/man/man3/getutmp.3.gz

l is a very handy tool that I use often.

It’s bigger and newer brother is lr, which emulates ls -R in a more reasonable way. It’s quite a mouthful:

lr() {
  zparseopts -D -E S=S t=t r=r h=h U=U l=l F=F d=d
  local sort="sort -t/ -k2"                                # by name (default)
  local numfmt="cat"
  local long='s:[^/]* /::; s:^\./\(.\):\1:;'               # strip detail
  local classify=''
  [[ -n $F ]] && classify='/^d/s:$:/:; /^-[^ ]*x/s:$:*:;'  # dir/ binary*
  [[ -n $l ]] && long='s: /\./\(.\): \1:; s: /\(.\): \1:;' # show detail
  [[ -n $S ]] && sort="sort -n -k5"                        # by size
  [[ -n $r ]] && sort+=" -r"                               # reverse
  [[ -n $t ]] && sort="sort -k6" && { [[ -n $r ]] || sort+=" -r" } # by date
  [[ -n $U ]] && sort=cat                                  # no sort, live output
  [[ -n $h ]] && numfmt="numfmt --field=5 --to=iec --padding=6"  # human fmt
  [[ -n $d ]] && set -- "$@" -prune                        # don't enter dirs
  find "$@" -printf "%M %2n %u %g %9s %TY-%Tm-%Td %TH:%TM /%p -> %l\n" |
    $=sort | $=numfmt |
    sed '/^[^l]/s/ -> $//; '$classify' '$long
}

A plain lr is like a find except for the stupid ./ at the beginning of every line:

% lr
.
bar
bar/bla
bar/quux
foo/
foo/a/
foo/a/b
foo/a/b/c

However, you can pass -l to get more detail (It even uses a reasonable date format. ;)):

% lr -lF
drwxrwxr-x  4 chris users        80 2013-06-29 16:28 ./
drwxrwxr-x  3 chris users        80 2013-06-29 16:28 bar/
drwxrwxr-x  2 chris users        40 2013-06-29 16:28 bar/bla/
-rw-rw-r--  1 chris users        57 2013-06-29 16:28 bar/quux
drwxrwxr-x  3 chris users        60 2013-06-29 16:28 foo/
drwxrwxr-x  3 chris users        60 2013-06-29 16:28 foo/a/
drwxrwxr-x  2 chris users        60 2013-06-29 16:29 foo/a/b/
-rw-rw-r--  1 chris users       317 2013-06-29 16:29 foo/a/b/c

The advantage is has is that it can sort over all arguments given. (By size, name, or date.) Compare:

% ls -lFRS bar foo/a/b 
bar:
total 4
-rw-rw-r-- 1 chris users 57 Jun 29 16:28 quux
drwxrwxr-x 2 chris users 40 Jun 29 16:28 bla/

bar/bla:
total 0

foo/a/b:
total 4
-rw-rw-r-- 1 chris users 317 Jun 29 16:29 c


% lr -lFS bar foo/a/b
drwxrwxr-x  2 chris users        40 2013-06-29 16:28 bar/bla/
-rw-rw-r--  1 chris users        57 2013-06-29 16:28 bar/quux
drwxrwxr-x  2 chris users        60 2013-06-29 16:29 foo/a/b/
drwxrwxr-x  3 chris users        80 2013-06-29 16:28 bar/
-rw-rw-r--  1 chris users       317 2013-06-29 16:29 foo/a/b/c

Also, it keeps relative paths for copy and pasting:

% ls -lF ../22
total 4
-rwxrwxr-x 1 chris users 2160 Nov  3  2004 fix-maildir-timestamps.pl*

% lr -lF ../22
drwxrwxr-x  2 chris users      4096 2013-06-03 21:28 ../22/
-rwxrwxr-x  1 chris users      2160 2004-11-03 18:32 ../22/fix-maildir-timestamps.pl*

If you look closely, you’ll see that other arguments are passed to find verbatim, so you can do more complex searches:

% lr -lF /usr/lib -size +80M
-rwxr-xr-x  1 root root  87749264 2013-06-20 06:25 /usr/lib/chromium/chromium*
-rw-r--r--  1 root root 143132030 2013-04-21 19:53 /usr/lib/ghc-7.6.3/ghc-7.6.3/libHSghc-7.6.3_p.a
-rw-r--r--  1 root root  85721136 2013-06-06 13:08 /usr/lib/maxima/5.30.0/binary-sbcl/maxima.core

I think lr is pretty much to how I actually want ls to work.

NP: Die Schnitter—Rebellenlied

Copyright © 2004–2022