23

What have I tried so far...

Command:

find . -type f -ctime -3 | tail -n 5

Result:

./Mobilni Telefoni/01. Box Update/05. DC Unlocker Client/dc-unlocker_client-1.00.0857.exe
./Mobilni Telefoni/01. Box Update/39. Z3X Box/01. Update/01. Samsung Box/SamsungTool_12.4.exe
./Mobilni Telefoni/10. Nokia/1. SRPSKI  HRVATSKI  JEZICI/BB5/3xx_Series/Asha 300/06.97/rm781_06.97_ppm_d.rar
./GPS Navigacije/01. Garmin/03. Garmin Other/garmin_kgen_15.exe
./GPS Navigacije/01. Garmin/03. Garmin Other/test.txt

This output is OK, doesn't work good if I put wider time span. (notice I use -ctime and not -mtime because some uploaded files are modified few years ago)

Problem is that files can be uploaded once a month, or once in a year, and I still need to get 10 latest files, regardless of time span.

If it can't be done, does tail only limit output, or somehow just fetches number specified without huge performance impact on large number of files.

By using command from one answer on SO, I was able to get the files but some files were missing...

find . -type f -printf '%T@ %p\n' | sort -n | tail -10 | cut -f2- -d" "

Result:

./Mobilni Telefoni/11. Samsung/1. FLASH FILES/1. SRPSKI HRVATSKI JEZICI/E/E2330/E2330_OXFKE2.rar
./Mobilni Telefoni/11. Samsung/1. FLASH FILES/1. SRPSKI HRVATSKI JEZICI/E/E2330/FlashTool_E2_R6.zip
./Mobilni Telefoni/11. Samsung/1. FLASH FILES/1. SRPSKI HRVATSKI JEZICI/E/E210/E210_XFGH2.rar
./Mobilni Telefoni/05. iPhone/07. iFaith/iFaith-v1.4.1_windows-final.zip
./Mobilni Telefoni/05. iPhone/09. iPhone Browser/SetupiPhoneBrowser.1.93.exe
./Mobilni Telefoni/05. iPhone/10. iPhone_PC_Suite/iPhone_PC_Suite_Eng_v0.2.1.rar
./Mobilni Telefoni/05. iPhone/10. iPhone_PC_Suite/iPhone_PC_Suite_Ok.rar
./test
./Mobilni Telefoni/11. Samsung/1. FLASH FILES/1. SRPSKI HRVATSKI JEZICI/E/E2152/E2152_XXJH4_OXFJI2.zip.filepart
./GPS Navigacije/01. Garmin/03. Garmin Other/test.txt

File garmin_kgen_15.exe is missing because it was created in 2008, but it was uploaded in last 24 hours.

Dejan Marjanović
  • 19,244
  • 7
  • 52
  • 66

3 Answers3

42

I was told that this is the solution:

find . -type f -printf "%C@ %p\n" | sort -rn | head -n 10

The key point is the printf %C@ placeholder, which is the -ctime one. I found it by reading man find.

Result:

1336992789.0000000000 ./Mobilni Telefoni/05. iPhone/03. iPhone 4G Firmware/5.1.1/iPhone3,1_5.1.1_9B206_Restore.ipsw.filepart
1336928538.0000000000 ./GPS Navigacije/01. Garmin/03. Garmin Other/test.txt
1336922295.0000000000 ./GPS Navigacije/01. Garmin/03. Garmin Other/garmin_kgen_15.exe
1336868365.0000000000 ./Mobilni Telefoni/11. Samsung/1. FLASH FILES/1. SRPSKI HRVATSKI JEZICI/E/E2152/E2152_XXJH4_OXFJI2.zip.filepart
1336867426.0000000000 ./Mobilni Telefoni/11. Samsung/1. FLASH FILES/1. SRPSKI HRVATSKI JEZICI/E/E210/E210_XFGH2.rar
1336866301.0000000000 ./Mobilni Telefoni/11. Samsung/1. FLASH FILES/1. SRPSKI HRVATSKI JEZICI/E/E2330/FlashTool_E2_R6.zip
1336865921.0000000000 ./Mobilni Telefoni/11. Samsung/1. FLASH FILES/1. SRPSKI HRVATSKI JEZICI/E/E2330/E2330_OXFKE2.rar
1336865409.0000000000 ./Mobilni Telefoni/11. Samsung/1. FLASH FILES/1. SRPSKI HRVATSKI JEZICI/E/E2230/E2230_XXKC1_CDS.zip
1336865398.0000000000 ./Mobilni Telefoni/11. Samsung/1. FLASH FILES/1. SRPSKI HRVATSKI JEZICI/E/E2230/E2230_XXKC1_BIN.zip
1336864949.0000000000 ./Mobilni Telefoni/11. Samsung/1. FLASH FILES/1. SRPSKI HRVATSKI JEZICI/E/E2230/E2230_OXFKC1_CSC.zip

For a very large list of files, sort(1) with pipes might not be optimal for resource usage.

sort(1) could be replaced with perl(1) and buffer the ten highest entries, only. This has been outlined in unix command: how to get top n records for three, here an adoption for ten records.

It replaces the sort(1) and head(1) filters:

find . -type f -printf "%C@ %p\n" | perl -ane '
    BEGIN {@top = ([-1]) x 10}
    if ($F[0] > $top[0][0]) {
        @top = sort {$a->[0] <=> $b->[0]} @top[1..9], [$F[0], $_];
    }
    END {print for reverse map {$_->[1]} @top}
'

The result is identical.

hakre
  • 193,403
  • 52
  • 435
  • 836
  • You forgot -n to sort. It should be: find . -type f -printf "%C@ %p\n" | sort -rn | head -n 10 – qwertzguy Mar 08 '13 at 15:43
  • Do you know what the default sorting mode is for sort? `-n` sounds fine though – hakre Mar 08 '13 at 15:56
  • It's alphabetical but it depends on the locale: http://unix.stackexchange.com/questions/43465/whats-the-default-order-of-linux-sort – qwertzguy Mar 08 '13 at 16:40
  • 1
    Simplified (and in chronological order): `find -printf "%C@ %p\n" | sort | tail`. – voices Jan 23 '17 at 14:49
  • If you want traditional `ls -l` output, you'd send the `head` (or per @tjt263 - `tail`) through a few more pipes: `...|cut -c23-|tr '\n' '\0'|xargs -0 ls -ld` -- I created a script for following large `scp` transfers that I can use with `watch`. – Rich Oct 18 '18 at 20:39
  • This is very inefficient for thousands of files, as `sort` maintains a fully sorted list rather than just the top N. – OrangeDog Jun 24 '21 at 10:43
  • @hakre I wrote a short python script to do it instead – OrangeDog Jun 24 '21 at 13:18
  • @hakre well one requires storing 10 records, and the other requires as many records as you have files. I don't know what you mean about buffering. – OrangeDog Jun 24 '21 at 15:30
  • @OrangeDog: Please find the `sort(1)` resource constraints addressed in the answer now, I updated it. It's even from this Q&A site. Filename portability is not addressed. Maybe a `pathchk(1)` filter. This pays off already on smaller lists for time constraints as I quickly tested. – hakre Jun 25 '21 at 12:31
0

I needed a solution to get the x latest modified files in a directory and use it afterwards in a loop to process them further:

find "/mnt/user/Movie" -iname '*.mkv' -printf "%C@ %p\n" | sort -n | cut -f2- -d" " | tail -10 | tr '\n' '\0' | 
    while IFS= read -r -d '' file; do 
        echo "$file"
    done

returns:

/mnt/user/Movie/IJ/I (2014)/I (2014).mkv
/mnt/user/Movie/AB/B (2010)/B (2010).mkv
/mnt/user/Movie/MN/N (1993)/N (1993).mkv
/mnt/user/Movie/MN/M (2016)/M (2016).mkv
/mnt/user/Movie/KL/K (1984)/K (1984).mkv
/mnt/user/Movie/MN/M (1999)/M (1999).mkv
/mnt/user/Movie/GH/G (2014)/G (2014).mkv
/mnt/user/Movie/MN/M (2002)/M (2002).mkv
/mnt/user/Movie/AB/B (2017)/B (2017).mkv
/mnt/user/Movie/CD/D (1997)/D (1997).mkv

Change tail -10 to the amount of files that should be returned. Of course you could replace -iname '*.mkv' against -type f to cover all files.

mgutt
  • 5,867
  • 2
  • 50
  • 77
-4

Easier:

filename=$(ls -t . | head -10)
Luis Andrés García
  • 5,852
  • 10
  • 43
  • 57