Monday, April 3, 2017

Variations around ls -lrt

I have been using almost compulsively ls -lrt for a long time now. As per the ls man page, this command lists the files of the current directory, with the latest files at the end, so that they are the ones that show up just above your next command-line. This is very convenient to work with, hmmm, not-so-well-organized directories, because it just shows what you're working on, and you can safely ignore the rest. Typical example is a big Downloads directory, for instance, but I use it everywhere. I quickly used alias lrt="ls -lrt" to make it easier, but... I though I might have as well a reliable way to directly use what I saw. So I came up with the following shell function (zsh, but probably works with most Bourne-like shells):
lrt() {
    ls -lrt "$@"
    lrt="$(ls -rt "$@" | tail -n1)"
This small function runs ls -lrt as usual, but also sets the $lrt shell variable to the latest file, so you can use it in your next commands ! Especially useful for complex file names. Demonstration:
22:05 vincent@ashitaka ~/Downloads lrt
-rw-r--r-- 1 vincent vincent   1490027 Apr  2 15:44
-rw-r--r-- 1 vincent vincent    668566 Apr  3 22:05 1-s2.0-S0013468617305947-main.pdf
22:06 vincent@ashitaka ~/Downloads cp -v $lrt ~/nice-paper.pdf
'1-s2.0-S0013468617305947-main.pdf' -> '/home/vincent/nice-paper.pdf'
This saves typing the name of the 1-s2.0-S0013468617305947-main.pdf: in this case, automatic completion doesn't help much, since many files in my Downloads directory start with the same orefix... I hope this helps !


jzags said...

It'd be cool to index the last N results from "ls -lrt", then you could do:

% lrt
% ln -s $lrt[0] most-recent.ogg
% ln -s $lrt[1] penultimate-file.ogg
% ln -s $lrt[2] a-little-while-ago.ogg

Thanks for the tip, though!

Vincent Fourmond said...

You bet this is something I have thought about too ;-) ! Better, even, index the latest by extension too.

A follow-up post, when I need it badly enough...

Philip Hands said...

You can avoid running ls twice, thus:

lrt() {
{ lrt=$(ls -ltr "$@" | tee /dev/fd/3 | tail -n1 | sed 's/^\(\S*\s*\)\{8\}//') ;} 3>&1

The sed might be a bit fragile, but at least this avoids the race condition that you have otherwise.

Philip Hands said...

actually, you don't need the tail either:

lrt() { { lrt=$(ls -ltr "$@" | tee /dev/fd/3 | sed -n '$s/^\(\S*\s*\)\{8\}//p') ;} 3>&1; }

Vincent Bernat said...

Since you use zsh, you can also use *(om[1]) to get the latest file, *(om[2]) for the previous one, etc.

Vincent Fourmond said...

@VincentBernat Wow ! I knew I should have had a closer look at extended globs, but this is just too useful. Thanks !

Vincent Fourmond said...

@Philip Using your strategy just prevents coloring, which is a very very very big plus... So, twice, it is !

Anonymous said...

Well, you can just strip the colour escapes out too:

lrt() { { lrt=$(ls -ltr --color "$@" | tee /dev/fd/3 | sed -n '${s/^\(\S*\s*\)\{8\}//;s/\o033\[[^m]*m//g;p}') ;} 3>&1; }