Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

In shell, how can I tail the latest file created in a directory?

share|improve this question

migrated from stackoverflow.com Mar 8 '10 at 19:17

This question came from our site for professional and enthusiast programmers.

    
come on closers, programmers need to tail! –  phaedrus Mar 8 '10 at 14:37
    
The close is only for moving to superuser or serverfault. The question will live there, and more people that might be interested will find it. –  Mnementh Mar 8 '10 at 15:14
    
The real problem here is finding the most recently update file in the directory and I believe that that has already been answered (either here or on Super User, I can't recall). –  dmckee Mar 8 '10 at 19:17
add comment

11 Answers 11

No no no! Do not parse the output of ls!

If you must do this I would recommend find

 tail -f $(find . -maxdepth 1 -type f -printf "%T@ %p\n" | sort -n | tail -n 1 | cut -d' ' -f 2-)

Or anything that isn't ls.

Parsing the output of ls is difficult and unreliable.

EDIT: added -maxdepth 1 per the comments. Don't code in haste!

share|improve this answer
1  
@AakashM: because you may get "surprising" results, e.g. if a file has "unusual" characters in its name (almost all characters are legal). –  John Zwinck Mar 8 '10 at 13:55
6  
People who use special characters in their file names deserve everything they get :-) –  paxdiablo Mar 8 '10 at 13:56
1  
This find is recursive, you could give a -maxdepth 1 to have it only find in the current directory. –  Wesho Mar 8 '10 at 14:10
3  
Seeing paxdiablo make that remark was painful enough, but then two people voted it up! People who write buggy software intentionally deserve everything they get. –  John Zwinck Mar 8 '10 at 14:10
2  
So the solution above doesn't work on osx due to lack of -printf option in find, but the following works only on osx due to differences in the stat command... maybe it will still help somebody tail -f $(find . -type f -exec stat -f "%m {}" {} \;| sort -n | tail -n 1 | cut -d ' ' -f 2) –  audio.zoom May 22 '12 at 17:59
show 5 more comments
tail `ls -t | head -1`

If you're worried about filenames with spaces,

tail "`ls -t | head -1`"
share|improve this answer
    
But what happens when your latest file has spaces or special characters? Use $() instead of `` and quote your subshell to avoid this problem. –  phogg Mar 8 '10 at 14:05
    
I like this. Clean and simple. As it should be. –  wic Mar 8 '10 at 14:28
    
It's easy to be clean and simple if you sacrifice robust and correct. –  phogg Mar 8 '10 at 14:43
    
Well, it depends on what you're doing, really. A solution that always works everywhere, for all possible filenames, is very nice, but in a constrained situation (log files, for example, with known non-weird names) it might be unnecessary. –  Pointy Mar 8 '10 at 14:49
add comment

On POSIX systems, there is no way of getting the "last created" directory entry. Each directory entry has atime, mtime and ctime, but contrary to Microsoft Windows, the ctime doesn't mean CreationTime, but "Time of last status change".

So the best you can get is to "tail the last recently modified file", which is explained in the other answers. I would go for this command:

tail -f "$(ls -tr | sed 1q)"

Note the quotes around the ls command. This makes the snippet work with almost all filenames.

share|improve this answer
    
Nice work. Straight to the point. +1 –  Norman Ramsey Mar 8 '10 at 15:13
    
+1 for citing correct atime/mtime/ctime meaning. –  phogg Mar 8 '10 at 18:42
add comment

I you just want to see the file size change you can use watch.

watch -d ls -l
share|improve this answer
add comment

You can use:

tail $(ls -1t | head -1)

The $() construct starts a sub-shell which runs the command ls -1t (listing all files in time order, one per line) and piping that through head -1 to get the first line (file).

The output of that command (the most recent file) is then passed to tail to be processed.

Keep in mind this runs the risk of getting a directory if that's the most recent directory entry created. I've used that trick in an alias to edit the most recent log file (from a rotating set) in a directory that contained only those log files.

share|improve this answer
    
The -1 isn't necessary, ls does that for you when it's in a pipe. Compare ls and ls|cat, for example. –  Dennis Williamson Mar 8 '10 at 14:27
    
That may be the case under Linux. In "true" Unix, processes didn't change their behaviour based on where their output was going. That would make pipeline debugging really annoying :-) –  paxdiablo Mar 8 '10 at 14:35
    
Hmmm, not sure that's correct -- ISTR having to issue "ls -C" to get column-formatted output under 4.2BSD when piping the output through a filter, and I'm pretty sure ls under Solaris works the same way. What is the "one, true Unix" anyway? –  TMN Mar 8 '10 at 15:14
    
Quotes! Quotes! Filenames have spaces in them! –  Norman Ramsey Mar 8 '10 at 15:14
    
@TMN: The one true Unix way is not to rely on ls for non-human consumers. "If the output is to a terminal, the format is implementation-defined." - this is the spec. If you want to be sure you have to say ls -1 or ls -C. –  phogg Mar 8 '10 at 19:08
add comment

There are probably a million ways to do this, but the way I would do it is this:

tail `ls -t | head -n 1`

The bits between the backticks (the quote like characters) are interpreted and the result returned to tail.

ls -t #gets the list of files in time order
head -n 1 # returns the first line only
share|improve this answer
1  
Backticks are evil. Use $() instead. –  William Pursell Mar 8 '10 at 17:10
add comment

A simple:

tail -f /path/to/directory/*

works just fine for me.

The problem is to get files that are generated after you started the tail command. But if you don't need that (as all the solutions above do not care for it), the asterisk is just simpler solution, IMO.

share|improve this answer
add comment
tail`ls -tr | tail -1`
share|improve this answer
    
You forgot a space there! –  Blacklight Shining Sep 8 '12 at 1:53
add comment

Someone posted it, and then erased it for some reason, but this is the only one that works, so...

tail -f `ls -tr | tail`
share|improve this answer
    
you've got to exclude directories, isnt it? –  phaedrus Mar 8 '10 at 13:55
1  
I posted this originally but I deleted it since I agree with Sorpigal that parsing output from ls isn't the smartest thing to do... –  ChristopheD Mar 8 '10 at 13:56
    
I need it quick and dirty, no directories in it. So, If you'll add your answer, I will accept that one –  Itay Moav -Malimovka Mar 8 '10 at 13:58
add comment
tail -f `ls -lt | grep -v ^d | head -2 | tail -1 | tr -s " " | cut -f 8 -d " "`

Explanation:

  • ls -lt: List of all files and directories sorted by modification time
  • grep -v ^d: exclude directories
  • head -2 onwards: parsing the needed filename
share|improve this answer
1  
+1 for clever, -2 for parsing ls output, -1 for not quoting the subshell, -1 for a magic "field 8" assumption (it's not portable!) and finally -1 for too clever. Overall score: -4. –  phogg Mar 8 '10 at 14:17
    
@Sorpigal Agreed. Happy to be the bad example though. –  phaedrus Mar 8 '10 at 14:23
    
yes didn't imagine it would be wrong on so many counts –  phaedrus Mar 8 '10 at 14:35
add comment
tail "$(ls -1tr|tail -1)"
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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