Bagaimana secara rekursif menemukan file termodifikasi dalam direktori?


Jawaban:


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

Untuk pohon besar, mungkin sulit untuk sortmenyimpan semuanya dalam ingatan.

%T@memberi Anda waktu modifikasi seperti cap waktu unix, sort -nmengurutkan secara numerik, tail -1mengambil baris terakhir (cap waktu tertinggi), cut -f2 -d" "memotong bidang pertama (timestamp) dari output.

Sunting: Sama seperti -printfmungkin hanya GNU, penggunaan tambahan stat -cjuga. Meskipun dimungkinkan untuk melakukan hal yang sama pada BSD, opsi untuk memformat berbeda ( -f "%m %N"sepertinya)

Dan saya merindukan bagian dari jamak; jika Anda menginginkan lebih dari file terbaru, cukup tambahkan argumen ekor.


7
Jika pesanan penting, Anda dapat beralih menggunakan sort -rn | head -3bukan sort -n | tail -3. Satu versi memberikan file dari yang terlama ke yang terbaru, sementara yang lain beralih dari yang terbaru ke terlama.
Don Faulkner

3
Saya memiliki direktori besar (sekitar sepuluh ribu file kecil) dan saya khawatir dengan kinerjanya, tapi ... perintah ini berjalan kurang dari satu detik! Hebat, terima kasih banyak !!! :-)
lucaferrario

2
"Untuk pohon besar, mungkin agak sulit untuk menyimpan semuanya dalam ingatan." sortakan membuat file sementara (dalam /tmp) sesuai kebutuhan, jadi saya tidak berpikir itu masalah.
Vladimir Panteleev

1
mengubahnya ke: -printf '%T@ %Tb %Td %TY %p\n'akan memberi Anda cap tanggal (jika perlu) (mirip dengan ls)
bshea

1
Saya menemukan yang berikut ini lebih pendek dan dengan keluaran yang lebih dapat diartikan:find . -type f -printf '%TF %TT %p\n' | sort | tail -1
snth

129

Menindaklanjuti jawaban @ plundra , inilah versi BSD dan OS X:

find . -type f -print0 | xargs -0 stat -f "%m %N" |
sort -rn | head -1 | cut -f2- -d" "

1
Apakah BSD / OS X findmendukung +bukan \;? Karena itu melakukan hal yang sama (melewati beberapa file sebagai parameter), tanpa -print0 | xargs -0pipa.
DevSolar

Apa yang harus saya lakukan jika saya ingin mendapatkan 5 terakhir atau jumlah file yang dimodifikasi dalam urutan menurun?
khunshan

@khunshan ubah head -1kehead -5
Emerson Farrugia

20

Alih-alih mengurutkan hasil dan hanya menyimpan hasil modifikasi terakhir, Anda dapat menggunakan awk untuk mencetak hanya hasil dengan waktu modifikasi terbesar (dalam waktu unix):

find . -type f -printf "%T@\0%p\0" | awk '
    {
        if ($0>max) {
            max=$0; 
            getline mostrecent
        } else 
            getline
    } 
    END{print mostrecent}' RS='\0'

Ini harus menjadi cara yang lebih cepat untuk menyelesaikan masalah Anda jika jumlah file cukup besar.

Saya telah menggunakan karakter NUL (yaitu '\ 0') karena, secara teoritis, nama file dapat berisi karakter apa pun (termasuk spasi dan baris baru) tetapi itu.

Jika Anda tidak memiliki nama pathologis dalam sistem Anda, Anda dapat menggunakan karakter baris baru juga:

find . -type f -printf "%T@\n%p\n" | awk '
    {
        if ($0>max) {
            max=$0; 
            getline mostrecent
        } else 
            getline
    } 
    END{print mostrecent}' RS='\n'

Selain itu, ini berfungsi di mawk juga.


Ini bisa dengan mudah diadaptasi untuk menjaga ketiganya menjadi yang terbaru.
Dijeda sampai pemberitahuan lebih lanjut.

1
Ini tidak bekerja dengan mawk, alternatif standar Debian.
Jan

Tidak, tetapi dalam hal ini Anda dapat menggunakan karakter baris baru jika itu tidak mengganggu Anda;)
marco

10

Saya mengalami kesulitan untuk menemukan file yang dimodifikasi terakhir di bawah Solaris 10. Tidak findada printfopsi dan stattidak tersedia. Saya menemukan solusi berikut yang bekerja dengan baik untuk saya:

find . -type f | sed 's/.*/"&"/' | xargs ls -E | awk '{ print $6," ",$7 }' | sort | tail -1

Untuk menampilkan nama file juga gunakan

find . -type f | sed 's/.*/"&"/' | xargs ls -E | awk '{ print $6," ",$7," ",$9 }' | sort | tail -1

Penjelasan

  • find . -type f menemukan dan mendaftar semua file
  • sed 's/.*/"&"/' membungkus pathname dalam tanda kutip untuk menangani spasi putih
  • xargs ls -Emengirimkan jalur yang dikutip ke ls, -Eopsi memastikan bahwa stempel waktu penuh (format tahun-bulan-hari-jam-menit-detik-nanoseconds ) dikembalikan
  • awk '{ print $6," ",$7 }' ekstrak hanya tanggal dan waktu
  • awk '{ print $6," ",$7," ",$9 }' ekstrak tanggal, waktu, dan nama file
  • sort mengembalikan file yang diurutkan berdasarkan tanggal
  • tail -1 hanya mengembalikan file yang terakhir dimodifikasi

9

Ini tampaknya berfungsi dengan baik, bahkan dengan subdirektori:

find . -type f | xargs ls -ltr | tail -n 1

Jika terlalu banyak file, perbaiki temuan.


1
The -lpilihan untuk lstampaknya tidak perlu. Hanya -trtampaknya cukup.
Acumenus

6
Ini sepertinya disortir per direktori, jadi itu tidak selalu menunjukkan file terbaru
Fabian Schmengler

1
Dalam hal ada ruang di jalur file yang lebih baik dilakukan:find . -type f -print0 | xargs -0 ls -ltr | tail -n 1
Pemeliharaan periodik

Ini tidak menemukan file terbaru untuk saya.
K.-Michael Aye

1
Pikirkan ini rusak jika ada spasi dalam nama file
waferthin

7

Memperlihatkan file terbaru dengan stempel waktu yang dapat dibaca manusia:

find . -type f -printf '%TY-%Tm-%Td %TH:%TM: %Tz %p\n'| sort -n | tail -n1

Hasilnya terlihat seperti ini:

2015-10-06 11:30: +0200 ./foo/bar.txt

Untuk menampilkan lebih banyak file, ganti -n1dengan nomor yang lebih tinggi


5

Saya menggunakan sesuatu yang serupa sepanjang waktu, serta daftar top-k dari file yang paling baru dimodifikasi. Untuk pohon direktori besar, bisa jadi lebih cepat untuk menghindari penyortiran . Dalam hal hanya file top-1 yang paling baru dimodifikasi:

find . -type f -printf '%T@ %p\n' | perl -ne '@a=split(/\s+/, $_, 2); ($t,$f)=@a if $a[0]>$t; print $f if eof()'

Pada direktori yang berisi 1,7 juta file, saya mendapatkan yang terbaru dalam 3.4s, kecepatan 7.5x terhadap solusi 25.5s menggunakan sort.


Sangat keren: Saya baru saja menukar cetakan terakhir dengan: system ("ls -l $ f") jika eof () untuk melihat tanggal dengan cara yang baik juga.
Martin T.

@ MartinT. : Hebat, dan sama-sama. Aneh bagi saya bahwa orang-orang memiliki naluri untuk mengurutkan hal-hal (O (n log n)) ketika metode O (n) tersedia. Ini sepertinya menjadi satu-satunya jawaban yang menghindari jenis. BTW, tujuan dari perintah yang saya sarankan adalah hanya untuk menemukan jalur file terbaru. Anda dapat alias perintah di shell Anda (misalnya sebagai lastfile) dan kemudian Anda dapat melakukan apa pun yang Anda suka dengan hasilnya, seperti ls -l $(lastfile .), atau open $(lastfile .)(pada Mac), dll.
Pierre D

Oh, saya benar: Saya melihat jawaban lain di bawah ini (@marco). +1.
Pierre D

4

Ini memberikan daftar yang diurutkan:

find . -type f -ls 2>/dev/null | sort -M -k8,10 | head -n5

Membalik urutan dengan menempatkan '-r' di perintah sortir. Jika Anda hanya ingin nama file, masukkan "awk '{print $ 11}' |" sebelum '| kepala'


3

Di Ubuntu 13, yang berikut melakukannya, mungkin sedikit lebih cepat, karena membalikkan pengurutan dan menggunakan 'head' alih-alih 'tail', mengurangi pekerjaan. Untuk menampilkan 11 file terbaru di pohon:

Temukan . -type f -printf '% T @% p \ n' | sort -n -r | kepala -11 | cut -f2- -d "" | sed -e's, ^. / ,, '| xargs ls -U -l

Ini memberikan daftar lengkap ls tanpa menyortir ulang dan menghilangkan './' yang mengganggu menempatkan 'pada setiap nama file.

Atau, sebagai fungsi bash:

treecent () {
  local numl
  if [[ 0 -eq $# ]] ; then
    numl=11   # Or whatever default you want.
  else
    numl=$1
  fi
  find . -type f -printf '%T@ %p\n' | sort -n -r | head -${numl} |  cut -f2- -d" " | sed -e 's,^\./,,' | xargs ls -U -l
}

Namun, sebagian besar pekerjaan dilakukan oleh solusi asli Plundra. Terima kasih, plundra.


3

Saya menghadapi masalah yang sama. Saya perlu menemukan file terbaru secara rekursif. menemukan butuh sekitar 50 menit untuk menemukan.

Berikut ini sedikit skrip untuk melakukannya lebih cepat:

#!/bin/sh

CURRENT_DIR='.'

zob () {
    FILE=$(ls -Art1 ${CURRENT_DIR} | tail -n 1)
    if [ ! -f ${FILE} ]; then
        CURRENT_DIR="${CURRENT_DIR}/${FILE}"
        zob
    fi
    echo $FILE
    exit
}
zob

Ini adalah fungsi rekursif yang mendapatkan item yang dimodifikasi terbaru dari direktori. Jika item ini adalah direktori, fungsinya disebut secara rekursif dan mencari ke direktori ini, dll.


3

Saya menemukan yang berikut ini lebih pendek dan dengan output yang lebih dapat diartikan:

find . -type f -printf '%TF %TT %p\n' | sort | tail -1

Mengingat panjang tetap dari format data ISO standar, pengurutan lexicographical baik-baik saja dan kami tidak membutuhkan -nopsi pada pengurutan.

Jika Anda ingin menghapus stempel waktu lagi, Anda dapat menggunakan:

find . -type f -printf '%TFT%TT %p\n' | sort | tail -1 | cut -f2- -d' '

2

Jika berjalan statpada setiap file satu per satu adalah memperlambat Anda dapat menggunakan xargsuntuk mempercepat beberapa hal:

find . -type f -print0 | xargs -0 stat -f "%m %N" | sort -n | tail -1 | cut -f2- -d" " 

2

Ini secara rekursif mengubah waktu modifikasi dari semua direktori di direktori saat ini ke file terbaru di setiap direktori:

for dir in */; do find $dir -type f -printf '%T@ "%p"\n' | sort -n | tail -1 | cut -f2- -d" " | xargs -I {} touch -r {} $dir; done

1
Ini rusak parah jika ada direktori berisi spasi - perlu mengatur IFS dan menggunakan tanda kutip: IFS = $ '\ n'; untuk dir dalam $ (temukan ./ -type d); lakukan echo "$ dir"; temukan "$ dir" -type f -printf '% T @ "% p" \ n' | sort -n | ekor -1 | cut -f2- -d "" | xargs -I {} touch -r {} "$ dir"; dilakukan;
Andy Lee Robinson

2

Klien sederhana ini juga akan berfungsi:

ls -1t | head -1

Anda dapat mengubah -1 ke jumlah file yang ingin Anda daftarkan


10
Tidak, itu tidak akan terjadi, karena tidak rekursif.
arataj

1

Saya menemukan perintah di atas berguna, tetapi untuk kasus saya, saya perlu melihat tanggal dan waktu file juga saya punya masalah dengan beberapa file yang memiliki spasi dalam nama-nama. Inilah solusi kerja saya.

find . -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d" " | sed 's/.*/"&"/' | xargs ls -l

1

Perintah berikut ini berfungsi pada Solaris:

find . -name "*zip" -type f | xargs ls -ltr | tail -1 

1

Mengabaikan file yang tersembunyi - dengan cap waktu yang bagus & cepat

$ find . -type f -not -path '*/\.*' -printf '%TY.%Tm.%Td %THh%TM %Ta %p\n' |sort -nr |head -n 10

Hasil

Menangani spasi dalam nama file dengan baik - bukan berarti ini harus digunakan!

2017.01.25 18h23 Wed ./indenting/Shifting blocks visually.mht
2016.12.11 12h33 Sun ./tabs/Converting tabs to spaces.mht
2016.12.02 01h46 Fri ./advocacy/2016.Vim or Emacs - Which text editor do you prefer?.mht
2016.11.09 17h05 Wed ./Word count - Vim Tips Wiki.mht

Lebih

Lebih find berlimpah mengikuti tautan.


1

Untuk mencari file di / target_directory dan semua sub-direktorinya, yang telah dimodifikasi dalam 60 menit terakhir:

$ find /target_directory -type f -mmin -60

Untuk menemukan file yang paling baru dimodifikasi, diurutkan dalam urutan terbalik dari waktu pembaruan (yaitu, file yang paling baru diperbarui terlebih dahulu):

$ find /etc -type f -printf '%TY-%Tm-%Td %TT %p\n' | sort -r

0

Saya lebih suka yang ini, lebih pendek:

find . -type f -print0|xargs -0 ls -drt|tail -n 1

0

Saya menulis paket pypi / github untuk pertanyaan ini karena saya memerlukan solusi juga.

https://github.com/bucknerns/logtail

Install:

pip install logtail

Penggunaan: ekor berganti file

logtail <log dir> [<glob match: default=*.log>]

Kegunaan2: Membuka file yang diubah terakhir di editor

editlatest <log dir> [<glob match: default=*.log>]
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.