7

System log files are serialized and I use ls -lrt to show me the most recent file. I then cat that file. This requires typing a long serial number each time.

How can I cat the last file appearing in my ls -lrt output in one command?

I'm using cygwin and the the output from ls -lrt foobar_job* look like this:

-

-rw-r--r-- 1 zundarz Domain Users   1133 Jul 31 16:54 foobar_job4855125.log
-rw-r--r-- 1 zundarz Domain Users   1256 Jul 31 17:10 foobar_job4855127.log
-rw-r--r-- 1 zundarz Domain Users   1389 Aug 11 10:20 foobar_job4887829.log
-rw-r--r-- 1 zundarz Domain Users   1228 Aug 11 10:39 foobar_job4887834.log
zundarz
  • 363

4 Answers4

18

If you're going to just cat a newest file in one command you don't really need -l option. On Linux and Cygwin you can use -1 option and make parsing much easier:

$ cat "$(ls -1rt | tail -n1)"

-1 should be very portable, it's specified in POSIX.

Also keep in mind that parsing ls output has its drawbacks.

EDIT:

As correctly noted in a comment by don_crissti you don't even need -1:

 $ cat "$(ls -rt | tail -n1)"
  • '-1' is really clever. – Minix Aug 14 '15 at 20:28
  • 3
    @Minix - not really, it's not needed in this case. Per the same standard this answer links to: The default format shall be to list one entry per line to standard output; the exceptions are to terminals or when one of the -C, -m, or -x options is specified. So in this case, it's already one entry per line, run ls | cat to see how it works... – don_crissti Aug 14 '15 at 20:49
  • @don_crissti: you're right, I added edit to my answer. Thx! – Arkadiusz Drabczyk Aug 14 '15 at 21:01
  • @don_crissti Even more clever! Guess I should really read the man pages more. – Minix Aug 15 '15 at 23:32
2

This method doesn't score highly in terms of correctness but should work in most cases: cat "$(ls -1t | head -n1)"

VaTo
  • 3,101
1

Tried it on my system and:

~$ cat "$(ls -lrt | tail -n 1 | tr -s ' ' | cut -d ' ' -f9-)"

worked.

ls -lrt

Gives the files ordered by their modification time (-t) in reverse order (-r).

tail -n 1

Gives you the last line of the output.

tr -s ''

Removes the repeat spaces in the line.

cut -d ' ' -f9-

Cuts the line on every space and gives you the 9th field, which is the file name. Adding - to the -f9 also gives all following fields, which is important for filenames containing spaces.

Alias

If you want to use the command as an alias, you have to escape the " characters.

That "'s in the command are necessary, because files can have spaces, which would be interpreted as more than one file by the cat command, if not enclosed by "'s.

It is also necessary to escape the $ sign. Otherwise the command inside $(...) would be executed once, when setting the alias and not every time the alias is called afterwards.

alias catrec="cat \"\$(ls -lrt | tail -n 1 | tr -s ' ' | cut -d ' ' -f9-)\""
Minix
  • 5,855
  • I tried to make alias out of it: alias catrec=' <your command> ', but it's not parsed correctly, it returns an error -f9)" not found. BTW, you command is the only one that worked for me. – Konrad Dec 27 '16 at 16:47
  • 1
    @Konrad That is because I also ' in my command. I will edit my answer to give a suitable solution. – Minix Dec 28 '16 at 22:40
-1

Bash one-liner (provided your filenames do not contain spaces):

cat $(ls -lrt | tail -1 | rev | cut -d" " -f1 | rev)

Explanation:

tail -1        # get last line of your ls
rev            # reverse characters order
cut -d" " -f1  # take first field using space as a separator

So the rev | cut -d" " -f1 | rev thing is a trick to be sure to get the last space-separated word without having to provide a platform dependent field number of character offset.