27

I can generate output sorted by date in "normal order" with the following command:

ls -A -lR | grep "^-" | sed "s/.\{43\}/&\n/" | grep -v "^-" | while read ONELINE; do if echo $ONELINE | cut -d " " -f3 | grep -o '[0-9][0-9]:[0-9][0-9]' > /dev/null 2>&1; then echo $ONELINE | sed "s/.\{7\}/&$(date +%Y) /"; else echo $ONELINE; fi; done

Result:

Jan 23 2011 10:42 SOMETHING 2007.12.20.avi
Jun 26 2009 SOMETHING 2009.06.25.avi
Feb 12 2010 SOMETHING 2010.02.11.avi
Jan 29 2011 09:17 SOMETHING 2011.01.27.avi
Feb 11 2011 20:06 SOMETHING 2011.02.10.avi
Feb 27 2011 23:05 SOMETHING 2011.02.24.avi

How could I get the output where the newest file is at the top, like this:

Feb 27 2011 23:05 SOMETHING 2011.02.24.avi
Feb 11 2011 20:06 SOMETHING 2011.02.10.avi
Jan 29 2011 09:17 SOMETHING 2011.01.27.avi
Jan 23 2011 10:42 SOMETHING 2007.12.20.avi
Feb 12 2010 SOMETHING 2010.02.11.avi
Jun 26 2009 SOMETHING 2009.06.25.avi
3
  • 2
    @user4724: how did yuo generate the list ?
    – user591
    Feb 28, 2011 at 20:30
  • @user4724: That doesn't generate the same type of outpout for me that you have - no matter as Gilles has the answer
    – user591
    Feb 28, 2011 at 21:46

7 Answers 7

31

On most unices, ls has a -t option. From the man page of my Debian box:

-t sort by modification time

Try the following command:

$ ls -lt

4
  • i need it recursively, sorry Feb 28, 2011 at 21:21
  • +ls -lt will list a full directory, if 1 file changes in it. Feb 28, 2011 at 21:22
  • The directories and files both not sorting for me as ls -ltr on CentOS Linux release 7.9.2009 Mar 9, 2022 at 10:01
  • @ChamindaBandara we're 10 years on from this answer, so you're probably better asking a new question. Reference this one, and provide not only the command you're using but also example input and results showing how it's not working for you Mar 9, 2022 at 15:51
20

Is that a text file you're trying to sort, or are you trying to view a directory listing by date? For the latter, use the -t flag to ls. For the former, see in particular the -M flag to GNU sort, which sorts by three-letter month name abbreviations. The following command sorts by the 3rd, 1st, 2nd and 4th columns, treating the second sort key as a month name.

sort -k 3 -k 1M -k2 -k4 in.txt

Do consider always using Japanese/ISO style dates, always in the order YYYY-MM-DD-HH-MM-SS (i.e. most significant first, constant column width). This way sorting by date is identical to a lexicographic sort.

3
  • Don't forget the leading zeroes on that date format suggestion. This is the format I use whenever I format the string myself. May 26, 2018 at 9:39
  • @stolenmoment You can use spaces instead of zeros if you don't mind spaces, the important point is a constant column with. 2018  5 26 works just as well as 2018 05 26 (as long as you don't go through markup that merges consecutive spaces…), what doesn't work well is 2018 5 26. May 26, 2018 at 10:39
  • Yeah, I reflexively avoid spaces in filenames, I'm sure you can guess why. May 26, 2018 at 11:34
7

I’m not sure if the functionality was in the ls command when the original question was asked, but now you can use the option --full-time.

e.g.,

ls -t --full-time 

will sort with oldest time at the bottom; or if you use:

ls -tr --full-time

then it will reverse the order.

4
  • The question is about how to sort file by modification date/time. The -t option answers that question completely; --full-time isn’t really relevant. Feb 17, 2017 at 21:05
  • The only thing -t option doesn't give you the year for files modified within six months where as --full-time gives you exactly that. You can also use time-style to format a date format to you liking. e.g ls -ltr --time-style+%Y-%m-%d\ %H:%M:%S Feb 20, 2017 at 8:35
  • I’m not sure what your point is.  ls -t doesn’t give you mode and owner of the files, the host name and operating system version, or the price of tea in China, either.  ls -t doesn’t even display the modification date at all.  But the question isn’t about displaying file information, it’s about sorting files by modification date.  You are not contributing to the answer of the question; you are adding nice-to-know supplementary information. When you get 50 reputation points, you can post that sort of information as a comment. Feb 21, 2017 at 0:52
  • Even though ls -t does not show other info(mode/owner/group), adding -l will do. I use ll -t and ll is a common alias ls -l which solves the problem. For me, it is confusing at first that for changes older than 6 months, the year columns shows year, while when it's <6 months old, it's showing hours; and --full-time solves that. For me it's valid answer. @G-ManSays'ReinstateMonica'
    – WesternGun
    Feb 14, 2022 at 11:49
1

I like the approach of using sort posted in the answer by Gilles 'SO- stop being evil', but it's not quite all the way there. First, technically the OP wants reverse chronological order, not forward, and so r needs to be addd to the sort criterial.
So starting with sort -k 3r -k 1Mr -k 2r -k 4r se.txt that would give you

Feb 27 2011 23:05 SOMETHING 2011.02.24.avi
Feb 11 2011 20:06 SOMETHING 2011.02.10.avi
Jan 23 2011 10:42 SOMETHING 2007.12.20.avi
Jan 29 2011 09:17 SOMETHING 2011.01.27.avi
Feb 12 2010 SOMETHING 2010.02.11.avi
Jun 26 2009 SOMETHING 2009.06.25.avi

But look closely and you'll note Jan 23, 2011 and Jan 29, 2011 are in the wrong order. This is due to a subtle bug, or perhaps unclear documentation in sort. An individual sort KEYDEF such as -k2 means starting from field 2, not only on field 2. It is best to also specify the stopping field as well (e.g. -k2,2 means sorting from field 2 to field 2, i.e. only field 2).

And so

sort -k 3,3r -k 1,1Mr -k 2,2r -k 4,4r

yields the correct results. (I was able to get this to work by setting only some of the stop fields in the KEYDEFs, but I don't know which are necessary and why, so it seems best to specify them all. Well, except maybe the last one, but then in the OP input file there are some records with 4 fields and some with 5 so the 4th field is not always the final field)

2
  • 1
    It's not a bug, it's as clearly specified in the manuals of most sort implementations and in the POSIX specification. See also Sort based on the third column Jan 18, 2022 at 17:08
  • I read GNU and BSD man pages. It is not clear at all to me why the first sort in my post fails. (Ignoring the 2 records that are only 4 fields)., it sorts 1st time by year-field then time-field then other things; 2nd time, using month criteria, by month-field, then day field, then time-field, then other things; 3rd time by day-field, then year-field, then time field, then other things, 4th time by other things. My reading of man page is that the day fields (col 2) get correctly sorted in the 3rd pass, and nothing should happen in the 4th (col 4+) pass to knock them out of order. Jan 18, 2022 at 19:33
1

This will list all files recursively with ls output and reverse sorted by modified time (mtime):

find -print0 -type f directory_path | xargs -0 ls -ltr

Peform the search more quickly with fd

fd -0 -t f directory_path | xargs -0 ls -ltr
3
  • (s/--type/-type/) That only works if file paths don't contain whitespace nor quotes nor backslashes and if the list of files is small enough that ls is invoked only once. Sep 15 at 6:16
  • @StéphaneChazelas Answer improved to address special chars. And as for ls invocation, the argument length limit on the vast majority of systems is 2Mib which means that even for an average full path of 100 characters, we still got a 20000 files batch. I believe that will be sufficient for >99% of people coming here.
    – adamency
    Sep 16 at 22:51
  • Should be find directory_path -type f -print0 | xargs -r0 ls -ltrd (wrong order of arguments for find; without -r, you'd end up with the current directory listed if find found no regular (-type f) files; -d not strictly necessary as ls should not be passed any directory files, but good habit to have when passing file lists to ls) Sep 19 at 16:33
0

With the standard -t option, ls will sort files (given as arguments or found in the contents of directories passed argument) by modification time from newest to oldest.

With the -R option, ls enters a recursive mode, but it still lists the contents of each directory separately, so while each directory listing will be listed by modification time, you won't get a notion of the relative time of files between different directories. The files will also not be listed with their full path.

To list files recursively with their full paths, ordered by time, you'd need to pass all of them by path to ls. You could do it with:

LC_ALL=C find . -name . -o -name '.*' -prune -o -exec ls -ltd {} +

(-name . -o -name '.*' -prune -o with LC_ALL=C to exclude hidden files, like ls does by default without -a/-A when it lists the contents of directories itself)

But that will break as soon as there are so many files that find needs to call ls several times to work around the execve() limit on the size or argument+environment that can be passed to a command, where you'll end up with several independent sorted lists.

To address that, you'd need to sort the list outside of ls and pass the list to those several invocations of ls -ld. With the zsh shell and a xargs that supports the -0 and -r option, that can be done with:

print -rNC1 -- **/*(Nom) | xargs -r0 ls -ltd --

If your ls supports the non-standard -U option to skip sorting, you can use that in place of -t as zsh has already sorted the list with its om (order by modification time) glob qualifier. Add the D glob qualifier if you want hidden files to be included.

With the GNU implementations of find, ls, cut and sort, you can also do:

LC_ALL=C find . -name . -o -name '.*' -prune -o -printf '%T@\t%P\0' |
  sort -rzn |
  cut -zf2- |
  xargs -r0 ls -lUd --
-4

recursive (R) and pause (|more)

ls -ltR |more
0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .