I have a folder with three files and basic contents:

$ tail *
==> file1 <==
file 1 contents

==> file2 <==
file 2 contents

==> file3 <==
file 3 contents

I would like to see the contents of the latest file using cat. I tried using it like this:

$ ls -ctr | tail -1

$ ls -ctr | tail -1 | cat

but as you can see, it only prints the name of the last file. I thought the pipe would take the output of tail and process the file with that name, like it does with the subshell command:

$ cat $(ls -ctr | tail -1)
file 3 contents

Why does the redirection method not work, and is there a way to accomplish this with pipes instead of the subshell?

  • Also you should read "Why you shouldn't parse the output of ls". If you're doing it interactively you might be fine, but if you're scripting, please don't do this. – Wildcard Jan 23 '16 at 1:01
  • More generally, though, you should clear up the difference between a command's arguments and a command's input. – Wildcard Jan 23 '16 at 1:03
set   ./file[123]            ### set an arg array of the glob resolution
while [ "${2+:}" ]           ### while there are at least 2 args
do    [ "$1" -nt "$2" ] &&   ### if $1 is newer than $2 then ...
      set "$@" "$1"; shift   ### reset the array to itself + $1; shift regardless
done; cat <"$1"              ### after loop cat $1 or report no glob match
  • 1
    I know you like simple "code only" answers and think they are self-explanatory...but they really could be greatly improved by adding explanations. :) At an absolute minimum if you just briefly said the names of the different features you are using, it would then allow an interested newcomer to at least know what words to put into a search engine to figure out your code. – Wildcard Jan 23 '16 at 9:16
  • 3
    @Wildcard - i welcome edits and would thank you for any you cared to contribute. but, as usual, you have a point... – mikeserv Jan 23 '16 at 9:36
  • 1
    Accepted because of the clear explanation of the code given. – user1717828 Jan 23 '16 at 17:12
  • @user1717828 - please look again at the edit - this fixes the subtle bug of the previous snippet's tendency to forever loop when ${1}t == ${2}t. This version will always prefer the last of two such in the lexical sort order. – mikeserv Jan 23 '16 at 17:34

You want to use the xargs command:

$ ls -ctr | tail -1 | xargs cat

This will take the STDOUT of the tail -1 command, and instead of using it as STDIN for the cat command will use it as options to the cat command.


You could try something like

less $(ls -ctr | tail - 1)

(the $(...) isn't universal, you might need to substitute backticks). Change less to taste.

  • > with pipes instead of the subshell? – user1717828 Jan 23 '16 at 0:47
  • @user1717828, a subshell is definitely cheaper that launching xargs – vonbrand Jan 23 '16 at 0:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.