how to `tail` the latest file in a directory












17














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.











  • 1




    come on closers, programmers need to tail!
    – amit
    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
















17














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.











  • 1




    come on closers, programmers need to tail!
    – amit
    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














17












17








17


3





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










share|improve this question













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







linux shell shell-script






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Mar 8 '10 at 13:46









Itay Moav -Malimovka

46961124




46961124




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


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






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


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










  • 1




    come on closers, programmers need to tail!
    – amit
    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














  • 1




    come on closers, programmers need to tail!
    – amit
    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








1




1




come on closers, programmers need to tail!
– amit
Mar 8 '10 at 14:37




come on closers, programmers need to tail!
– amit
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 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




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










12 Answers
12






active

oldest

votes


















22














Do not parse the output of ls! Parsing the output of ls is difficult and unreliable.



If you must do this I recommend using find. Originally I had here a simple example merely to give you the gist of the solution, but since this answer seems somewhat popular I decided to revise this to provide a version that is safe to copy/paste and use with all inputs. Are you sitting comfortably? We'll start with a oneliner that will give you the latest file in the current directory:



tail -- "$(find . -maxdepth 1 -type f -printf '%T@.%p' | sort -znr -t. -k1,2 | while IFS= read -r -d '' -r record ; do printf '%s' "$record" | cut -d. -f3- ; break ; done)"


Not quite a oneliner now, is it? Here it is again as a shell function and formatted for easier reading:



latest-file-in-directory () {
find "${@:-.}" -maxdepth 1 -type f -printf '%T@.%p' |
sort -znr -t. -k1,2 |
while IFS= read -r -d '' -r record ; do
printf '%s' "$record" | cut -d. -f3-
break
done
}


And now that as a oneliner:



tail -- "$(latest-file-in-directory)"


If all else fails you can include the above function in your .bashrc and consider the problem solved, with one caveat. If you just wanted to get the job done you need not read further.



The caveat with this is that a file name ending in one or more newlines will still not be passed to tail correctly. Working around this problem is complicated and I consider it sufficient that if such a malicious file name is encountered the relatively safe behavior of encountering a "No such file" error will occur instead of anything more dangerous.



Juicy details



For the curious this is the tedious explanation of how it works, why it's safe and why other methods probably aren't.



Danger, Will Robinson



First of all, the only byte that is safe to delimit file paths is null because it is the only byte universally forbidden in file paths on Unix systems. It is important when handling any list of file paths to only use null as a delimiter and, when handing even a single file path from one program to another, to do so in a manner which will not choke on arbitrary bytes. There are many seemingly-correct ways to solve this and other problems which fail by assuming (even accidentally) that file names will not have either new lines or spaces in them. Neither assumption is safe.



For today's purposes step one is to get a null-delimited list of files out of find. This is pretty easy if you have a find supporting -print0 such as GNU's:



find . -print0


But this list still does not tell us which one is newest, so we need to include that information. I choose to use find's -printf switch which lets me specify what data appears in the output. Not all versions of find support -printf (it is not standard) but GNU find does. If you find yourself without -printf you will need to rely on -exec stat {} ; at which point you must give up all hope of portability as stat is not standard either. For now I'm going to move on assuming you have GNU tools.



find . -printf '%T@.%p'


Here I am asking for printf format %T@ which is the modification time in seconds since the beginning of the Unix epoch followed by a period and then followed by a number indicating fractions of a second. I add to this another period and then %p (which is the full path to the file) before ending with a null byte.



Now I have



find . -maxdepth 1 ! -type d -printf '%T@.%p'


It may go without saying but for the sake of being complete -maxdepth 1 prevents find from listing the contents of sub directories and ! -type d skips directories which you are unlikely to want to tail. So far I have files in the current directory with modification time information, so now I need to sort by that modification time.



Getting it in the right order



By default sort expects its input to be newline-delimited records. If you have GNU sort you can ask it to expect null-delimited records instead by using the -z switch.; for standard sort there is no solution. I am only interested in sorting by the first two numbers (seconds and fractions of a second) and don't want to sort by the actual file name so I tell sort two things: First, that it should consider the period (.) a field delimiter and second that it should only use the first and second fields when considering how to sort the records.



| sort -znr -t. -k1,2


First of all I am bundling three short options that take no value together; -znr is just a concise way of saying -z -n -r). After that -t . (the space is optional) tells sort the field delimiter character and -k 1,2 specifies the field numbers: first and second (sort counts fields from one, not zero). Remember that a sample record for the current directory would look like:



1000000000.0000000000../some-file-name


This means sort will look at first 1000000000 and then 0000000000 when ordering this record. The -n option tells sort to use numeric comparison when comparing these values, because both values are numbers. This may not be important since the numbers are of fixed length but it does no harm.



The other switch given to sort is -r for "reverse." By default the output of a numeric sort will be lowest numbers first, -r changes it so that it lists the lowest numbers last and the highest numbers first. Since these numbers are timestamps higher will mean newer and this puts the newest record at the beginning of the list.



Just the important bits



As the list of file paths emerges from sort it now has the desired answer we're looking for right at the top. What remains is to find a way to discard the other records and to strip the timestamp. Unfortunately even GNU head and tail do not accept switches to make them operate on null-delimited input. Instead I use a while loop as a kind of poor man's head.



| while IFS= read -r -d '' record


First I unset IFS so that the list of files is not subjected to word splitting. Next I tell read two things: Do not interpret escape sequences in the input (-r) and the input is delimited with a null byte (-d); here the empty string '' is used to indicate "no delimiter" aka delimited by null. Each record will be read in to the variable record so that each time the while loop iterates it has a single timestamp and a single file name. Note that -d is a GNU extension; if you have only a standard read this technique will not work and you have little recourse.



We know that the record variable has three parts to it, all delimited by period characters. Using the cut utility it is possible to extract a portion of them.



printf '%s' "$record" | cut -d. -f3-


Here the entire record is passed to printf and from there piped to cut; in bash you could simplify this further using a here string to cut -d. -3f- <<<"$record" for better performance. We tell cut two things: First with -d that it should a specific delimiter for identifying fields (as with sort the delimiter . is used). Second cut is instructed with -f to print only values from specific fields; the field list is given as a range 3- which indicates the value from the third field and from all following fields. This means that cut will read and ignore everything up to and including the second . that it finds in the record and then will print the remainder, which is the file path portion.



Having printed the newest file path there's no need to keep going: break exits the loop without letting it move on to the second file path.



The only thing that remains is running tail on the file path returned by this pipeline. You may have noticed in my example that I did this by enclosing the pipeline in a subshell; what you may not have noticed is that I enclosed the subshell in double quotes. This is important because at the last even with all of this effort to be safe for any file names an unquoted subshell expansion could still break things. A more detailed explanation is available if you're interested. The second important but easily-overlooked aspect to the invocation of tail is that I provided the option -- to it before expanding the file name. This will instruct tail that no more options are being specified and everything following is a file name, which makes it safe to handle file names that begin with -.






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






  • 5




    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






  • 3




    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






  • 2




    "Unfortunately even GNU head and tail do not accept switches to make them operate on null-delimited input." My replacement for head: … | grep -zm <number> "".
    – Kamil Maciorowski
    Aug 17 '17 at 20:29



















18














tail `ls -t | head -1`


If you're worried about filenames with spaces,



tail "`ls -t | head -1`"





share|improve this answer

















  • 1




    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






  • 4




    It's easy to be clean and simple if you sacrifice robust and correct.
    – phogg
    Mar 8 '10 at 14:43






  • 1




    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










  • This is the cleanest solution so far. Thank you!
    – demisx
    Mar 4 '16 at 0:29



















4














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



















4














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



watch -d ls -l





share|improve this answer





























    3














    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



















    3














    In zsh:



    tail *(.om[1])


    See: http://zsh.sourceforge.net/Doc/Release/Expansion.html#Glob-Qualifiers, here m denotes modification time m[Mwhms][-|+]n, and the preceding o means that it is sorted in one way (O sorts it the other way). The . means only regular files. Within the brackets [1] picks the first item. To pick three use [1,3], to get the oldest use [-1].



    It's nice short and doesn't use ls.






    share|improve this answer





























      1














      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

















      • 2




        Backticks are evil. Use $() instead.
        – William Pursell
        Mar 8 '10 at 17:10



















      1














      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





























        0














        tail`ls -tr | tail -1`





        share|improve this answer





















        • You forgot a space there!
          – Blacklight Shining
          Sep 8 '12 at 1:53



















        0














        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?
          – amit
          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



















        0














        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.
          – amit
          Mar 8 '10 at 14:23










        • yes didn't imagine it would be wrong on so many counts
          – amit
          Mar 8 '10 at 14:35



















        0














        tail "$(ls -1tr|tail -1)"





        share|improve this answer





















          Your Answer








          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "3"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fsuperuser.com%2fquestions%2f117596%2fhow-to-tail-the-latest-file-in-a-directory%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          12 Answers
          12






          active

          oldest

          votes








          12 Answers
          12






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          22














          Do not parse the output of ls! Parsing the output of ls is difficult and unreliable.



          If you must do this I recommend using find. Originally I had here a simple example merely to give you the gist of the solution, but since this answer seems somewhat popular I decided to revise this to provide a version that is safe to copy/paste and use with all inputs. Are you sitting comfortably? We'll start with a oneliner that will give you the latest file in the current directory:



          tail -- "$(find . -maxdepth 1 -type f -printf '%T@.%p' | sort -znr -t. -k1,2 | while IFS= read -r -d '' -r record ; do printf '%s' "$record" | cut -d. -f3- ; break ; done)"


          Not quite a oneliner now, is it? Here it is again as a shell function and formatted for easier reading:



          latest-file-in-directory () {
          find "${@:-.}" -maxdepth 1 -type f -printf '%T@.%p' |
          sort -znr -t. -k1,2 |
          while IFS= read -r -d '' -r record ; do
          printf '%s' "$record" | cut -d. -f3-
          break
          done
          }


          And now that as a oneliner:



          tail -- "$(latest-file-in-directory)"


          If all else fails you can include the above function in your .bashrc and consider the problem solved, with one caveat. If you just wanted to get the job done you need not read further.



          The caveat with this is that a file name ending in one or more newlines will still not be passed to tail correctly. Working around this problem is complicated and I consider it sufficient that if such a malicious file name is encountered the relatively safe behavior of encountering a "No such file" error will occur instead of anything more dangerous.



          Juicy details



          For the curious this is the tedious explanation of how it works, why it's safe and why other methods probably aren't.



          Danger, Will Robinson



          First of all, the only byte that is safe to delimit file paths is null because it is the only byte universally forbidden in file paths on Unix systems. It is important when handling any list of file paths to only use null as a delimiter and, when handing even a single file path from one program to another, to do so in a manner which will not choke on arbitrary bytes. There are many seemingly-correct ways to solve this and other problems which fail by assuming (even accidentally) that file names will not have either new lines or spaces in them. Neither assumption is safe.



          For today's purposes step one is to get a null-delimited list of files out of find. This is pretty easy if you have a find supporting -print0 such as GNU's:



          find . -print0


          But this list still does not tell us which one is newest, so we need to include that information. I choose to use find's -printf switch which lets me specify what data appears in the output. Not all versions of find support -printf (it is not standard) but GNU find does. If you find yourself without -printf you will need to rely on -exec stat {} ; at which point you must give up all hope of portability as stat is not standard either. For now I'm going to move on assuming you have GNU tools.



          find . -printf '%T@.%p'


          Here I am asking for printf format %T@ which is the modification time in seconds since the beginning of the Unix epoch followed by a period and then followed by a number indicating fractions of a second. I add to this another period and then %p (which is the full path to the file) before ending with a null byte.



          Now I have



          find . -maxdepth 1 ! -type d -printf '%T@.%p'


          It may go without saying but for the sake of being complete -maxdepth 1 prevents find from listing the contents of sub directories and ! -type d skips directories which you are unlikely to want to tail. So far I have files in the current directory with modification time information, so now I need to sort by that modification time.



          Getting it in the right order



          By default sort expects its input to be newline-delimited records. If you have GNU sort you can ask it to expect null-delimited records instead by using the -z switch.; for standard sort there is no solution. I am only interested in sorting by the first two numbers (seconds and fractions of a second) and don't want to sort by the actual file name so I tell sort two things: First, that it should consider the period (.) a field delimiter and second that it should only use the first and second fields when considering how to sort the records.



          | sort -znr -t. -k1,2


          First of all I am bundling three short options that take no value together; -znr is just a concise way of saying -z -n -r). After that -t . (the space is optional) tells sort the field delimiter character and -k 1,2 specifies the field numbers: first and second (sort counts fields from one, not zero). Remember that a sample record for the current directory would look like:



          1000000000.0000000000../some-file-name


          This means sort will look at first 1000000000 and then 0000000000 when ordering this record. The -n option tells sort to use numeric comparison when comparing these values, because both values are numbers. This may not be important since the numbers are of fixed length but it does no harm.



          The other switch given to sort is -r for "reverse." By default the output of a numeric sort will be lowest numbers first, -r changes it so that it lists the lowest numbers last and the highest numbers first. Since these numbers are timestamps higher will mean newer and this puts the newest record at the beginning of the list.



          Just the important bits



          As the list of file paths emerges from sort it now has the desired answer we're looking for right at the top. What remains is to find a way to discard the other records and to strip the timestamp. Unfortunately even GNU head and tail do not accept switches to make them operate on null-delimited input. Instead I use a while loop as a kind of poor man's head.



          | while IFS= read -r -d '' record


          First I unset IFS so that the list of files is not subjected to word splitting. Next I tell read two things: Do not interpret escape sequences in the input (-r) and the input is delimited with a null byte (-d); here the empty string '' is used to indicate "no delimiter" aka delimited by null. Each record will be read in to the variable record so that each time the while loop iterates it has a single timestamp and a single file name. Note that -d is a GNU extension; if you have only a standard read this technique will not work and you have little recourse.



          We know that the record variable has three parts to it, all delimited by period characters. Using the cut utility it is possible to extract a portion of them.



          printf '%s' "$record" | cut -d. -f3-


          Here the entire record is passed to printf and from there piped to cut; in bash you could simplify this further using a here string to cut -d. -3f- <<<"$record" for better performance. We tell cut two things: First with -d that it should a specific delimiter for identifying fields (as with sort the delimiter . is used). Second cut is instructed with -f to print only values from specific fields; the field list is given as a range 3- which indicates the value from the third field and from all following fields. This means that cut will read and ignore everything up to and including the second . that it finds in the record and then will print the remainder, which is the file path portion.



          Having printed the newest file path there's no need to keep going: break exits the loop without letting it move on to the second file path.



          The only thing that remains is running tail on the file path returned by this pipeline. You may have noticed in my example that I did this by enclosing the pipeline in a subshell; what you may not have noticed is that I enclosed the subshell in double quotes. This is important because at the last even with all of this effort to be safe for any file names an unquoted subshell expansion could still break things. A more detailed explanation is available if you're interested. The second important but easily-overlooked aspect to the invocation of tail is that I provided the option -- to it before expanding the file name. This will instruct tail that no more options are being specified and everything following is a file name, which makes it safe to handle file names that begin with -.






          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






          • 5




            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






          • 3




            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






          • 2




            "Unfortunately even GNU head and tail do not accept switches to make them operate on null-delimited input." My replacement for head: … | grep -zm <number> "".
            – Kamil Maciorowski
            Aug 17 '17 at 20:29
















          22














          Do not parse the output of ls! Parsing the output of ls is difficult and unreliable.



          If you must do this I recommend using find. Originally I had here a simple example merely to give you the gist of the solution, but since this answer seems somewhat popular I decided to revise this to provide a version that is safe to copy/paste and use with all inputs. Are you sitting comfortably? We'll start with a oneliner that will give you the latest file in the current directory:



          tail -- "$(find . -maxdepth 1 -type f -printf '%T@.%p' | sort -znr -t. -k1,2 | while IFS= read -r -d '' -r record ; do printf '%s' "$record" | cut -d. -f3- ; break ; done)"


          Not quite a oneliner now, is it? Here it is again as a shell function and formatted for easier reading:



          latest-file-in-directory () {
          find "${@:-.}" -maxdepth 1 -type f -printf '%T@.%p' |
          sort -znr -t. -k1,2 |
          while IFS= read -r -d '' -r record ; do
          printf '%s' "$record" | cut -d. -f3-
          break
          done
          }


          And now that as a oneliner:



          tail -- "$(latest-file-in-directory)"


          If all else fails you can include the above function in your .bashrc and consider the problem solved, with one caveat. If you just wanted to get the job done you need not read further.



          The caveat with this is that a file name ending in one or more newlines will still not be passed to tail correctly. Working around this problem is complicated and I consider it sufficient that if such a malicious file name is encountered the relatively safe behavior of encountering a "No such file" error will occur instead of anything more dangerous.



          Juicy details



          For the curious this is the tedious explanation of how it works, why it's safe and why other methods probably aren't.



          Danger, Will Robinson



          First of all, the only byte that is safe to delimit file paths is null because it is the only byte universally forbidden in file paths on Unix systems. It is important when handling any list of file paths to only use null as a delimiter and, when handing even a single file path from one program to another, to do so in a manner which will not choke on arbitrary bytes. There are many seemingly-correct ways to solve this and other problems which fail by assuming (even accidentally) that file names will not have either new lines or spaces in them. Neither assumption is safe.



          For today's purposes step one is to get a null-delimited list of files out of find. This is pretty easy if you have a find supporting -print0 such as GNU's:



          find . -print0


          But this list still does not tell us which one is newest, so we need to include that information. I choose to use find's -printf switch which lets me specify what data appears in the output. Not all versions of find support -printf (it is not standard) but GNU find does. If you find yourself without -printf you will need to rely on -exec stat {} ; at which point you must give up all hope of portability as stat is not standard either. For now I'm going to move on assuming you have GNU tools.



          find . -printf '%T@.%p'


          Here I am asking for printf format %T@ which is the modification time in seconds since the beginning of the Unix epoch followed by a period and then followed by a number indicating fractions of a second. I add to this another period and then %p (which is the full path to the file) before ending with a null byte.



          Now I have



          find . -maxdepth 1 ! -type d -printf '%T@.%p'


          It may go without saying but for the sake of being complete -maxdepth 1 prevents find from listing the contents of sub directories and ! -type d skips directories which you are unlikely to want to tail. So far I have files in the current directory with modification time information, so now I need to sort by that modification time.



          Getting it in the right order



          By default sort expects its input to be newline-delimited records. If you have GNU sort you can ask it to expect null-delimited records instead by using the -z switch.; for standard sort there is no solution. I am only interested in sorting by the first two numbers (seconds and fractions of a second) and don't want to sort by the actual file name so I tell sort two things: First, that it should consider the period (.) a field delimiter and second that it should only use the first and second fields when considering how to sort the records.



          | sort -znr -t. -k1,2


          First of all I am bundling three short options that take no value together; -znr is just a concise way of saying -z -n -r). After that -t . (the space is optional) tells sort the field delimiter character and -k 1,2 specifies the field numbers: first and second (sort counts fields from one, not zero). Remember that a sample record for the current directory would look like:



          1000000000.0000000000../some-file-name


          This means sort will look at first 1000000000 and then 0000000000 when ordering this record. The -n option tells sort to use numeric comparison when comparing these values, because both values are numbers. This may not be important since the numbers are of fixed length but it does no harm.



          The other switch given to sort is -r for "reverse." By default the output of a numeric sort will be lowest numbers first, -r changes it so that it lists the lowest numbers last and the highest numbers first. Since these numbers are timestamps higher will mean newer and this puts the newest record at the beginning of the list.



          Just the important bits



          As the list of file paths emerges from sort it now has the desired answer we're looking for right at the top. What remains is to find a way to discard the other records and to strip the timestamp. Unfortunately even GNU head and tail do not accept switches to make them operate on null-delimited input. Instead I use a while loop as a kind of poor man's head.



          | while IFS= read -r -d '' record


          First I unset IFS so that the list of files is not subjected to word splitting. Next I tell read two things: Do not interpret escape sequences in the input (-r) and the input is delimited with a null byte (-d); here the empty string '' is used to indicate "no delimiter" aka delimited by null. Each record will be read in to the variable record so that each time the while loop iterates it has a single timestamp and a single file name. Note that -d is a GNU extension; if you have only a standard read this technique will not work and you have little recourse.



          We know that the record variable has three parts to it, all delimited by period characters. Using the cut utility it is possible to extract a portion of them.



          printf '%s' "$record" | cut -d. -f3-


          Here the entire record is passed to printf and from there piped to cut; in bash you could simplify this further using a here string to cut -d. -3f- <<<"$record" for better performance. We tell cut two things: First with -d that it should a specific delimiter for identifying fields (as with sort the delimiter . is used). Second cut is instructed with -f to print only values from specific fields; the field list is given as a range 3- which indicates the value from the third field and from all following fields. This means that cut will read and ignore everything up to and including the second . that it finds in the record and then will print the remainder, which is the file path portion.



          Having printed the newest file path there's no need to keep going: break exits the loop without letting it move on to the second file path.



          The only thing that remains is running tail on the file path returned by this pipeline. You may have noticed in my example that I did this by enclosing the pipeline in a subshell; what you may not have noticed is that I enclosed the subshell in double quotes. This is important because at the last even with all of this effort to be safe for any file names an unquoted subshell expansion could still break things. A more detailed explanation is available if you're interested. The second important but easily-overlooked aspect to the invocation of tail is that I provided the option -- to it before expanding the file name. This will instruct tail that no more options are being specified and everything following is a file name, which makes it safe to handle file names that begin with -.






          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






          • 5




            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






          • 3




            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






          • 2




            "Unfortunately even GNU head and tail do not accept switches to make them operate on null-delimited input." My replacement for head: … | grep -zm <number> "".
            – Kamil Maciorowski
            Aug 17 '17 at 20:29














          22












          22








          22






          Do not parse the output of ls! Parsing the output of ls is difficult and unreliable.



          If you must do this I recommend using find. Originally I had here a simple example merely to give you the gist of the solution, but since this answer seems somewhat popular I decided to revise this to provide a version that is safe to copy/paste and use with all inputs. Are you sitting comfortably? We'll start with a oneliner that will give you the latest file in the current directory:



          tail -- "$(find . -maxdepth 1 -type f -printf '%T@.%p' | sort -znr -t. -k1,2 | while IFS= read -r -d '' -r record ; do printf '%s' "$record" | cut -d. -f3- ; break ; done)"


          Not quite a oneliner now, is it? Here it is again as a shell function and formatted for easier reading:



          latest-file-in-directory () {
          find "${@:-.}" -maxdepth 1 -type f -printf '%T@.%p' |
          sort -znr -t. -k1,2 |
          while IFS= read -r -d '' -r record ; do
          printf '%s' "$record" | cut -d. -f3-
          break
          done
          }


          And now that as a oneliner:



          tail -- "$(latest-file-in-directory)"


          If all else fails you can include the above function in your .bashrc and consider the problem solved, with one caveat. If you just wanted to get the job done you need not read further.



          The caveat with this is that a file name ending in one or more newlines will still not be passed to tail correctly. Working around this problem is complicated and I consider it sufficient that if such a malicious file name is encountered the relatively safe behavior of encountering a "No such file" error will occur instead of anything more dangerous.



          Juicy details



          For the curious this is the tedious explanation of how it works, why it's safe and why other methods probably aren't.



          Danger, Will Robinson



          First of all, the only byte that is safe to delimit file paths is null because it is the only byte universally forbidden in file paths on Unix systems. It is important when handling any list of file paths to only use null as a delimiter and, when handing even a single file path from one program to another, to do so in a manner which will not choke on arbitrary bytes. There are many seemingly-correct ways to solve this and other problems which fail by assuming (even accidentally) that file names will not have either new lines or spaces in them. Neither assumption is safe.



          For today's purposes step one is to get a null-delimited list of files out of find. This is pretty easy if you have a find supporting -print0 such as GNU's:



          find . -print0


          But this list still does not tell us which one is newest, so we need to include that information. I choose to use find's -printf switch which lets me specify what data appears in the output. Not all versions of find support -printf (it is not standard) but GNU find does. If you find yourself without -printf you will need to rely on -exec stat {} ; at which point you must give up all hope of portability as stat is not standard either. For now I'm going to move on assuming you have GNU tools.



          find . -printf '%T@.%p'


          Here I am asking for printf format %T@ which is the modification time in seconds since the beginning of the Unix epoch followed by a period and then followed by a number indicating fractions of a second. I add to this another period and then %p (which is the full path to the file) before ending with a null byte.



          Now I have



          find . -maxdepth 1 ! -type d -printf '%T@.%p'


          It may go without saying but for the sake of being complete -maxdepth 1 prevents find from listing the contents of sub directories and ! -type d skips directories which you are unlikely to want to tail. So far I have files in the current directory with modification time information, so now I need to sort by that modification time.



          Getting it in the right order



          By default sort expects its input to be newline-delimited records. If you have GNU sort you can ask it to expect null-delimited records instead by using the -z switch.; for standard sort there is no solution. I am only interested in sorting by the first two numbers (seconds and fractions of a second) and don't want to sort by the actual file name so I tell sort two things: First, that it should consider the period (.) a field delimiter and second that it should only use the first and second fields when considering how to sort the records.



          | sort -znr -t. -k1,2


          First of all I am bundling three short options that take no value together; -znr is just a concise way of saying -z -n -r). After that -t . (the space is optional) tells sort the field delimiter character and -k 1,2 specifies the field numbers: first and second (sort counts fields from one, not zero). Remember that a sample record for the current directory would look like:



          1000000000.0000000000../some-file-name


          This means sort will look at first 1000000000 and then 0000000000 when ordering this record. The -n option tells sort to use numeric comparison when comparing these values, because both values are numbers. This may not be important since the numbers are of fixed length but it does no harm.



          The other switch given to sort is -r for "reverse." By default the output of a numeric sort will be lowest numbers first, -r changes it so that it lists the lowest numbers last and the highest numbers first. Since these numbers are timestamps higher will mean newer and this puts the newest record at the beginning of the list.



          Just the important bits



          As the list of file paths emerges from sort it now has the desired answer we're looking for right at the top. What remains is to find a way to discard the other records and to strip the timestamp. Unfortunately even GNU head and tail do not accept switches to make them operate on null-delimited input. Instead I use a while loop as a kind of poor man's head.



          | while IFS= read -r -d '' record


          First I unset IFS so that the list of files is not subjected to word splitting. Next I tell read two things: Do not interpret escape sequences in the input (-r) and the input is delimited with a null byte (-d); here the empty string '' is used to indicate "no delimiter" aka delimited by null. Each record will be read in to the variable record so that each time the while loop iterates it has a single timestamp and a single file name. Note that -d is a GNU extension; if you have only a standard read this technique will not work and you have little recourse.



          We know that the record variable has three parts to it, all delimited by period characters. Using the cut utility it is possible to extract a portion of them.



          printf '%s' "$record" | cut -d. -f3-


          Here the entire record is passed to printf and from there piped to cut; in bash you could simplify this further using a here string to cut -d. -3f- <<<"$record" for better performance. We tell cut two things: First with -d that it should a specific delimiter for identifying fields (as with sort the delimiter . is used). Second cut is instructed with -f to print only values from specific fields; the field list is given as a range 3- which indicates the value from the third field and from all following fields. This means that cut will read and ignore everything up to and including the second . that it finds in the record and then will print the remainder, which is the file path portion.



          Having printed the newest file path there's no need to keep going: break exits the loop without letting it move on to the second file path.



          The only thing that remains is running tail on the file path returned by this pipeline. You may have noticed in my example that I did this by enclosing the pipeline in a subshell; what you may not have noticed is that I enclosed the subshell in double quotes. This is important because at the last even with all of this effort to be safe for any file names an unquoted subshell expansion could still break things. A more detailed explanation is available if you're interested. The second important but easily-overlooked aspect to the invocation of tail is that I provided the option -- to it before expanding the file name. This will instruct tail that no more options are being specified and everything following is a file name, which makes it safe to handle file names that begin with -.






          share|improve this answer














          Do not parse the output of ls! Parsing the output of ls is difficult and unreliable.



          If you must do this I recommend using find. Originally I had here a simple example merely to give you the gist of the solution, but since this answer seems somewhat popular I decided to revise this to provide a version that is safe to copy/paste and use with all inputs. Are you sitting comfortably? We'll start with a oneliner that will give you the latest file in the current directory:



          tail -- "$(find . -maxdepth 1 -type f -printf '%T@.%p' | sort -znr -t. -k1,2 | while IFS= read -r -d '' -r record ; do printf '%s' "$record" | cut -d. -f3- ; break ; done)"


          Not quite a oneliner now, is it? Here it is again as a shell function and formatted for easier reading:



          latest-file-in-directory () {
          find "${@:-.}" -maxdepth 1 -type f -printf '%T@.%p' |
          sort -znr -t. -k1,2 |
          while IFS= read -r -d '' -r record ; do
          printf '%s' "$record" | cut -d. -f3-
          break
          done
          }


          And now that as a oneliner:



          tail -- "$(latest-file-in-directory)"


          If all else fails you can include the above function in your .bashrc and consider the problem solved, with one caveat. If you just wanted to get the job done you need not read further.



          The caveat with this is that a file name ending in one or more newlines will still not be passed to tail correctly. Working around this problem is complicated and I consider it sufficient that if such a malicious file name is encountered the relatively safe behavior of encountering a "No such file" error will occur instead of anything more dangerous.



          Juicy details



          For the curious this is the tedious explanation of how it works, why it's safe and why other methods probably aren't.



          Danger, Will Robinson



          First of all, the only byte that is safe to delimit file paths is null because it is the only byte universally forbidden in file paths on Unix systems. It is important when handling any list of file paths to only use null as a delimiter and, when handing even a single file path from one program to another, to do so in a manner which will not choke on arbitrary bytes. There are many seemingly-correct ways to solve this and other problems which fail by assuming (even accidentally) that file names will not have either new lines or spaces in them. Neither assumption is safe.



          For today's purposes step one is to get a null-delimited list of files out of find. This is pretty easy if you have a find supporting -print0 such as GNU's:



          find . -print0


          But this list still does not tell us which one is newest, so we need to include that information. I choose to use find's -printf switch which lets me specify what data appears in the output. Not all versions of find support -printf (it is not standard) but GNU find does. If you find yourself without -printf you will need to rely on -exec stat {} ; at which point you must give up all hope of portability as stat is not standard either. For now I'm going to move on assuming you have GNU tools.



          find . -printf '%T@.%p'


          Here I am asking for printf format %T@ which is the modification time in seconds since the beginning of the Unix epoch followed by a period and then followed by a number indicating fractions of a second. I add to this another period and then %p (which is the full path to the file) before ending with a null byte.



          Now I have



          find . -maxdepth 1 ! -type d -printf '%T@.%p'


          It may go without saying but for the sake of being complete -maxdepth 1 prevents find from listing the contents of sub directories and ! -type d skips directories which you are unlikely to want to tail. So far I have files in the current directory with modification time information, so now I need to sort by that modification time.



          Getting it in the right order



          By default sort expects its input to be newline-delimited records. If you have GNU sort you can ask it to expect null-delimited records instead by using the -z switch.; for standard sort there is no solution. I am only interested in sorting by the first two numbers (seconds and fractions of a second) and don't want to sort by the actual file name so I tell sort two things: First, that it should consider the period (.) a field delimiter and second that it should only use the first and second fields when considering how to sort the records.



          | sort -znr -t. -k1,2


          First of all I am bundling three short options that take no value together; -znr is just a concise way of saying -z -n -r). After that -t . (the space is optional) tells sort the field delimiter character and -k 1,2 specifies the field numbers: first and second (sort counts fields from one, not zero). Remember that a sample record for the current directory would look like:



          1000000000.0000000000../some-file-name


          This means sort will look at first 1000000000 and then 0000000000 when ordering this record. The -n option tells sort to use numeric comparison when comparing these values, because both values are numbers. This may not be important since the numbers are of fixed length but it does no harm.



          The other switch given to sort is -r for "reverse." By default the output of a numeric sort will be lowest numbers first, -r changes it so that it lists the lowest numbers last and the highest numbers first. Since these numbers are timestamps higher will mean newer and this puts the newest record at the beginning of the list.



          Just the important bits



          As the list of file paths emerges from sort it now has the desired answer we're looking for right at the top. What remains is to find a way to discard the other records and to strip the timestamp. Unfortunately even GNU head and tail do not accept switches to make them operate on null-delimited input. Instead I use a while loop as a kind of poor man's head.



          | while IFS= read -r -d '' record


          First I unset IFS so that the list of files is not subjected to word splitting. Next I tell read two things: Do not interpret escape sequences in the input (-r) and the input is delimited with a null byte (-d); here the empty string '' is used to indicate "no delimiter" aka delimited by null. Each record will be read in to the variable record so that each time the while loop iterates it has a single timestamp and a single file name. Note that -d is a GNU extension; if you have only a standard read this technique will not work and you have little recourse.



          We know that the record variable has three parts to it, all delimited by period characters. Using the cut utility it is possible to extract a portion of them.



          printf '%s' "$record" | cut -d. -f3-


          Here the entire record is passed to printf and from there piped to cut; in bash you could simplify this further using a here string to cut -d. -3f- <<<"$record" for better performance. We tell cut two things: First with -d that it should a specific delimiter for identifying fields (as with sort the delimiter . is used). Second cut is instructed with -f to print only values from specific fields; the field list is given as a range 3- which indicates the value from the third field and from all following fields. This means that cut will read and ignore everything up to and including the second . that it finds in the record and then will print the remainder, which is the file path portion.



          Having printed the newest file path there's no need to keep going: break exits the loop without letting it move on to the second file path.



          The only thing that remains is running tail on the file path returned by this pipeline. You may have noticed in my example that I did this by enclosing the pipeline in a subshell; what you may not have noticed is that I enclosed the subshell in double quotes. This is important because at the last even with all of this effort to be safe for any file names an unquoted subshell expansion could still break things. A more detailed explanation is available if you're interested. The second important but easily-overlooked aspect to the invocation of tail is that I provided the option -- to it before expanding the file name. This will instruct tail that no more options are being specified and everything following is a file name, which makes it safe to handle file names that begin with -.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Dec 5 at 20:43









          matrixanomaly

          1033




          1033










          answered Mar 8 '10 at 13:52









          phogg

          769411




          769411








          • 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






          • 5




            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






          • 3




            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






          • 2




            "Unfortunately even GNU head and tail do not accept switches to make them operate on null-delimited input." My replacement for head: … | grep -zm <number> "".
            – Kamil Maciorowski
            Aug 17 '17 at 20:29














          • 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






          • 5




            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






          • 3




            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






          • 2




            "Unfortunately even GNU head and tail do not accept switches to make them operate on null-delimited input." My replacement for head: … | grep -zm <number> "".
            – Kamil Maciorowski
            Aug 17 '17 at 20:29








          1




          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




          @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




          6




          People who use special characters in their file names deserve everything they get :-)
          – paxdiablo
          Mar 8 '10 at 13:56




          People who use special characters in their file names deserve everything they get :-)
          – paxdiablo
          Mar 8 '10 at 13:56




          5




          5




          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




          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




          3




          3




          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




          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




          2




          2




          "Unfortunately even GNU head and tail do not accept switches to make them operate on null-delimited input." My replacement for head: … | grep -zm <number> "".
          – Kamil Maciorowski
          Aug 17 '17 at 20:29




          "Unfortunately even GNU head and tail do not accept switches to make them operate on null-delimited input." My replacement for head: … | grep -zm <number> "".
          – Kamil Maciorowski
          Aug 17 '17 at 20:29













          18














          tail `ls -t | head -1`


          If you're worried about filenames with spaces,



          tail "`ls -t | head -1`"





          share|improve this answer

















          • 1




            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






          • 4




            It's easy to be clean and simple if you sacrifice robust and correct.
            – phogg
            Mar 8 '10 at 14:43






          • 1




            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










          • This is the cleanest solution so far. Thank you!
            – demisx
            Mar 4 '16 at 0:29
















          18














          tail `ls -t | head -1`


          If you're worried about filenames with spaces,



          tail "`ls -t | head -1`"





          share|improve this answer

















          • 1




            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






          • 4




            It's easy to be clean and simple if you sacrifice robust and correct.
            – phogg
            Mar 8 '10 at 14:43






          • 1




            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










          • This is the cleanest solution so far. Thank you!
            – demisx
            Mar 4 '16 at 0:29














          18












          18








          18






          tail `ls -t | head -1`


          If you're worried about filenames with spaces,



          tail "`ls -t | head -1`"





          share|improve this answer












          tail `ls -t | head -1`


          If you're worried about filenames with spaces,



          tail "`ls -t | head -1`"






          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Mar 8 '10 at 13:49









          Pointy

          5931520




          5931520








          • 1




            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






          • 4




            It's easy to be clean and simple if you sacrifice robust and correct.
            – phogg
            Mar 8 '10 at 14:43






          • 1




            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










          • This is the cleanest solution so far. Thank you!
            – demisx
            Mar 4 '16 at 0:29














          • 1




            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






          • 4




            It's easy to be clean and simple if you sacrifice robust and correct.
            – phogg
            Mar 8 '10 at 14:43






          • 1




            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










          • This is the cleanest solution so far. Thank you!
            – demisx
            Mar 4 '16 at 0:29








          1




          1




          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




          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




          I like this. Clean and simple. As it should be.
          – wic
          Mar 8 '10 at 14:28




          4




          4




          It's easy to be clean and simple if you sacrifice robust and correct.
          – phogg
          Mar 8 '10 at 14:43




          It's easy to be clean and simple if you sacrifice robust and correct.
          – phogg
          Mar 8 '10 at 14:43




          1




          1




          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




          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












          This is the cleanest solution so far. Thank you!
          – demisx
          Mar 4 '16 at 0:29




          This is the cleanest solution so far. Thank you!
          – demisx
          Mar 4 '16 at 0:29











          4














          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
















          4














          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














          4












          4








          4






          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












          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












          share|improve this answer



          share|improve this answer










          answered Mar 8 '10 at 14:24









          Roland Illig

          25615




          25615












          • Nice work. Straight to the point. +1
            – Norman Ramsey
            Mar 8 '10 at 15:13


















          • Nice work. Straight to the point. +1
            – Norman Ramsey
            Mar 8 '10 at 15:13
















          Nice work. Straight to the point. +1
          – Norman Ramsey
          Mar 8 '10 at 15:13




          Nice work. Straight to the point. +1
          – Norman Ramsey
          Mar 8 '10 at 15:13











          4














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



          watch -d ls -l





          share|improve this answer


























            4














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



            watch -d ls -l





            share|improve this answer
























              4












              4








              4






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



              watch -d ls -l





              share|improve this answer












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



              watch -d ls -l






              share|improve this answer












              share|improve this answer



              share|improve this answer










              answered Oct 31 '12 at 14:00









              tpal

              411




              411























                  3














                  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
















                  3














                  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














                  3












                  3








                  3






                  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












                  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












                  share|improve this answer



                  share|improve this answer










                  answered Mar 8 '10 at 13:50







                  user53528



















                  • 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


















                  • 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
















                  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




                  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




                  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




                  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




                  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




                  @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











                  3














                  In zsh:



                  tail *(.om[1])


                  See: http://zsh.sourceforge.net/Doc/Release/Expansion.html#Glob-Qualifiers, here m denotes modification time m[Mwhms][-|+]n, and the preceding o means that it is sorted in one way (O sorts it the other way). The . means only regular files. Within the brackets [1] picks the first item. To pick three use [1,3], to get the oldest use [-1].



                  It's nice short and doesn't use ls.






                  share|improve this answer


























                    3














                    In zsh:



                    tail *(.om[1])


                    See: http://zsh.sourceforge.net/Doc/Release/Expansion.html#Glob-Qualifiers, here m denotes modification time m[Mwhms][-|+]n, and the preceding o means that it is sorted in one way (O sorts it the other way). The . means only regular files. Within the brackets [1] picks the first item. To pick three use [1,3], to get the oldest use [-1].



                    It's nice short and doesn't use ls.






                    share|improve this answer
























                      3












                      3








                      3






                      In zsh:



                      tail *(.om[1])


                      See: http://zsh.sourceforge.net/Doc/Release/Expansion.html#Glob-Qualifiers, here m denotes modification time m[Mwhms][-|+]n, and the preceding o means that it is sorted in one way (O sorts it the other way). The . means only regular files. Within the brackets [1] picks the first item. To pick three use [1,3], to get the oldest use [-1].



                      It's nice short and doesn't use ls.






                      share|improve this answer












                      In zsh:



                      tail *(.om[1])


                      See: http://zsh.sourceforge.net/Doc/Release/Expansion.html#Glob-Qualifiers, here m denotes modification time m[Mwhms][-|+]n, and the preceding o means that it is sorted in one way (O sorts it the other way). The . means only regular files. Within the brackets [1] picks the first item. To pick three use [1,3], to get the oldest use [-1].



                      It's nice short and doesn't use ls.







                      share|improve this answer












                      share|improve this answer



                      share|improve this answer










                      answered Nov 24 '15 at 9:50









                      Anne van Rossum

                      186110




                      186110























                          1














                          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

















                          • 2




                            Backticks are evil. Use $() instead.
                            – William Pursell
                            Mar 8 '10 at 17:10
















                          1














                          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

















                          • 2




                            Backticks are evil. Use $() instead.
                            – William Pursell
                            Mar 8 '10 at 17:10














                          1












                          1








                          1






                          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












                          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












                          share|improve this answer



                          share|improve this answer










                          answered Mar 8 '10 at 13:57









                          iblamefish

                          1113




                          1113








                          • 2




                            Backticks are evil. Use $() instead.
                            – William Pursell
                            Mar 8 '10 at 17:10














                          • 2




                            Backticks are evil. Use $() instead.
                            – William Pursell
                            Mar 8 '10 at 17:10








                          2




                          2




                          Backticks are evil. Use $() instead.
                          – William Pursell
                          Mar 8 '10 at 17:10




                          Backticks are evil. Use $() instead.
                          – William Pursell
                          Mar 8 '10 at 17:10











                          1














                          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


























                            1














                            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
























                              1












                              1








                              1






                              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












                              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












                              share|improve this answer



                              share|improve this answer










                              answered Jul 5 '12 at 2:59









                              bruno.braga

                              311136




                              311136























                                  0














                                  tail`ls -tr | tail -1`





                                  share|improve this answer





















                                  • You forgot a space there!
                                    – Blacklight Shining
                                    Sep 8 '12 at 1:53
















                                  0














                                  tail`ls -tr | tail -1`





                                  share|improve this answer





















                                  • You forgot a space there!
                                    – Blacklight Shining
                                    Sep 8 '12 at 1:53














                                  0












                                  0








                                  0






                                  tail`ls -tr | tail -1`





                                  share|improve this answer












                                  tail`ls -tr | tail -1`






                                  share|improve this answer












                                  share|improve this answer



                                  share|improve this answer










                                  answered Mar 8 '10 at 13:48









                                  user22644

                                  33915




                                  33915












                                  • You forgot a space there!
                                    – Blacklight Shining
                                    Sep 8 '12 at 1:53


















                                  • You forgot a space there!
                                    – Blacklight Shining
                                    Sep 8 '12 at 1:53
















                                  You forgot a space there!
                                  – Blacklight Shining
                                  Sep 8 '12 at 1:53




                                  You forgot a space there!
                                  – Blacklight Shining
                                  Sep 8 '12 at 1:53











                                  0














                                  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?
                                    – amit
                                    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
















                                  0














                                  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?
                                    – amit
                                    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














                                  0












                                  0








                                  0






                                  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












                                  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












                                  share|improve this answer



                                  share|improve this answer










                                  answered Mar 8 '10 at 13:54









                                  Itay Moav -Malimovka

                                  46961124




                                  46961124












                                  • you've got to exclude directories, isnt it?
                                    – amit
                                    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


















                                  • you've got to exclude directories, isnt it?
                                    – amit
                                    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
















                                  you've got to exclude directories, isnt it?
                                  – amit
                                  Mar 8 '10 at 13:55




                                  you've got to exclude directories, isnt it?
                                  – amit
                                  Mar 8 '10 at 13:55




                                  1




                                  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 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




                                  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











                                  0














                                  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.
                                    – amit
                                    Mar 8 '10 at 14:23










                                  • yes didn't imagine it would be wrong on so many counts
                                    – amit
                                    Mar 8 '10 at 14:35
















                                  0














                                  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.
                                    – amit
                                    Mar 8 '10 at 14:23










                                  • yes didn't imagine it would be wrong on so many counts
                                    – amit
                                    Mar 8 '10 at 14:35














                                  0












                                  0








                                  0






                                  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












                                  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












                                  share|improve this answer



                                  share|improve this answer










                                  answered Mar 8 '10 at 13:58









                                  amit

                                  8110




                                  8110








                                  • 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.
                                    – amit
                                    Mar 8 '10 at 14:23










                                  • yes didn't imagine it would be wrong on so many counts
                                    – amit
                                    Mar 8 '10 at 14:35














                                  • 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.
                                    – amit
                                    Mar 8 '10 at 14:23










                                  • yes didn't imagine it would be wrong on so many counts
                                    – amit
                                    Mar 8 '10 at 14:35








                                  1




                                  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




                                  +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.
                                  – amit
                                  Mar 8 '10 at 14:23




                                  @Sorpigal Agreed. Happy to be the bad example though.
                                  – amit
                                  Mar 8 '10 at 14:23












                                  yes didn't imagine it would be wrong on so many counts
                                  – amit
                                  Mar 8 '10 at 14:35




                                  yes didn't imagine it would be wrong on so many counts
                                  – amit
                                  Mar 8 '10 at 14:35











                                  0














                                  tail "$(ls -1tr|tail -1)"





                                  share|improve this answer


























                                    0














                                    tail "$(ls -1tr|tail -1)"





                                    share|improve this answer
























                                      0












                                      0








                                      0






                                      tail "$(ls -1tr|tail -1)"





                                      share|improve this answer












                                      tail "$(ls -1tr|tail -1)"






                                      share|improve this answer












                                      share|improve this answer



                                      share|improve this answer










                                      answered Mar 8 '10 at 14:21









                                      user31894

                                      2,105129




                                      2,105129






























                                          draft saved

                                          draft discarded




















































                                          Thanks for contributing an answer to Super User!


                                          • Please be sure to answer the question. Provide details and share your research!

                                          But avoid



                                          • Asking for help, clarification, or responding to other answers.

                                          • Making statements based on opinion; back them up with references or personal experience.


                                          To learn more, see our tips on writing great answers.





                                          Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                                          Please pay close attention to the following guidance:


                                          • Please be sure to answer the question. Provide details and share your research!

                                          But avoid



                                          • Asking for help, clarification, or responding to other answers.

                                          • Making statements based on opinion; back them up with references or personal experience.


                                          To learn more, see our tips on writing great answers.




                                          draft saved


                                          draft discarded














                                          StackExchange.ready(
                                          function () {
                                          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fsuperuser.com%2fquestions%2f117596%2fhow-to-tail-the-latest-file-in-a-directory%23new-answer', 'question_page');
                                          }
                                          );

                                          Post as a guest















                                          Required, but never shown





















































                                          Required, but never shown














                                          Required, but never shown












                                          Required, but never shown







                                          Required, but never shown

































                                          Required, but never shown














                                          Required, but never shown












                                          Required, but never shown







                                          Required, but never shown







                                          Popular posts from this blog

                                          Plaza Victoria

                                          Puebla de Zaragoza

                                          Musa