Saya mencari shell one-liner untuk menemukan file tertua di pohon direktori.
Saya mencari shell one-liner untuk menemukan file tertua di pohon direktori.
Jawaban:
Ini berfungsi (diperbarui untuk memasukkan saran Daniel Andersson):
find -type f -printf '%T+ %p\n' | sort | head -n 1
find
kosong karena saya memiliki nama file yang mengandung baris baru.
Yang ini sedikit lebih portabel dan karena tidak bergantung pada find
ekstensi GNU -printf
, jadi ini berfungsi pada BSD / OS X juga:
find . -type f -print0 | xargs -0 ls -ltr | head -n 1
Satu-satunya downside di sini adalah bahwa itu agak terbatas pada ukuran ARG_MAX
(yang seharusnya tidak relevan untuk kebanyakan kernel yang lebih baru). Jadi, jika ada lebih dari getconf ARG_MAX
karakter yang dikembalikan (262.144 di sistem saya), itu tidak memberi Anda hasil yang benar. Ini juga tidak sesuai dengan POSIX karena -print0
dan xargs -0
tidak.
Beberapa solusi lebih lanjut untuk masalah ini diuraikan di sini: Bagaimana saya bisa menemukan file terbaru (terbaru, paling awal, tertua) dalam direktori? - Greg's Wiki
xargs: ls: terminated by signal 13
kesalahan sebagai efek samping. Saya menduga itu SIGPIPE. Saya tidak tahu mengapa saya tidak mendapatkan kesalahan yang sama ketika saya menyortir output sort ke head dalam solusi saya.
head
perintah yang berhenti setelah membaca baris dan dengan demikian "mematahkan" pipa, saya pikir. Anda tidak mendapatkan kesalahan karena sort
tampaknya tidak mengeluh tentang hal itu, tetapi ls
melakukannya dalam kasus lain.
xargs
perlu dipanggil ls
lebih dari sekali. Dalam hal ini, output yang diurutkan dari beberapa pemanggilan itu berakhir disatukan ketika mereka harus digabung.
ls
melakukannya dan melihat file tertua, solusi Anda mungkin akan melampaui batas panjang baris perintah, yang menyebabkan ls
dipanggil beberapa kali. Anda akan mendapatkan jawaban yang salah tetapi Anda tidak akan pernah tahu.
Perintah perintah berikut dijamin untuk bekerja dengan segala jenis nama file aneh:
find -type f -printf "%T+ %p\0" | sort -z | grep -zom 1 ".*" | cat
find -type f -printf "%T@ %T+ %p\0" | \
sort -nz | grep -zom 1 ".*" | sed 's/[^ ]* //'
stat -c "%y %n" "$(find -type f -printf "%T@ %p\0" | \
sort -nz | grep -zom 1 ".*" | sed 's/[^ ]* //')"
Menggunakan byte nol ( \0
) alih-alih karakter linefeed ( \n
) memastikan output dari find masih dapat dimengerti jika salah satu nama file berisi karakter linefeed.
The -z
switch membuat kedua mengurutkan dan grep menafsirkan hanya byte null sebagai end-of-line karakter. Karena tidak ada saklar untuk head, kami menggunakan grep -m 1
(hanya satu kejadian).
Perintah diperintahkan oleh waktu eksekusi (diukur pada mesin saya).
Perintah pertama akan menjadi yang paling lambat karena harus mengubah waktu setiap file menjadi format yang dapat dibaca manusia terlebih dahulu dan kemudian mengurutkan string tersebut. Perpipaan ke kucing menghindari pewarnaan hasil.
Perintah kedua sedikit lebih cepat. Sementara itu masih melakukan konversi tanggal, penyortiran numerik ( sort -n
) detik berlalu sejak zaman Unix sedikit lebih cepat. sed menghapus detik sejak zaman Unix.
Perintah terakhir tidak melakukan konversi sama sekali dan harus secara signifikan lebih cepat daripada dua yang pertama. Perintah find sendiri tidak akan menampilkan mtime dari file terlama, jadi stat diperlukan.
Meskipun jawaban yang diterima dan yang lainnya di sini melakukan pekerjaan, jika Anda memiliki pohon yang sangat besar, semuanya akan mengurutkan seluruh file.
Lebih baik jika kita bisa daftar mereka dan melacak yang tertua, tanpa perlu menyortir sama sekali.
Itulah mengapa saya datang dengan solusi alternatif ini:
ls -lRU $PWD/* | awk 'BEGIN {cont=0; oldd=strftime("%Y%m%d"); } { gsub(/-/,"",$6); if (substr($1,0,1)=="/") { pat=substr($1,0,length($0)-1)"/"; }; if( $6 != "") {if ( $6 < oldd ) { oldd=$6; oldf=pat$8; }; print $6, pat$8; count++;}} END { print "Oldest date: ", oldd, "\nFile:", oldf, "\nTotal compared: ", count}'
Saya harap ini bisa membantu, bahkan jika pertanyaannya agak lama.
Sunting 1: perubahan ini memungkinkan penguraian file dan direktori dengan spasi. Cukup cepat untuk mengeluarkannya di root /
dan menemukan file terlama yang pernah ada.
ls -lRU --time-style=long-iso "$PWD"/* | awk 'BEGIN {cont=0; oldd=strftime("%Y%m%d"); } { gsub(/-/,"",$6); if (substr($0,0,1)=="/") { pat=substr($0,0,length($0)-1)"/"; $6="" }; if( $6 ~ /^[0-9]+$/) {if ( $6 < oldd ) { oldd=$6; oldf=$8; for(i=9; i<=NF; i++) oldf=oldf $i; oldf=pat oldf; }; count++;}} END { print "Oldest date: ", oldd, "\nFile:", oldf, "\nTotal compared: ", count}'
Perintah dijelaskan:
Menjalankannya:
~ $ time ls -lRU "$ PWD" / * | awk dll.
Tanggal terlama: 19691231
File: /home/.../.../backupold/.../EXAMPLES/how-to-program.txt
Total dibandingkan: 111438
0m1.135s nyata
pengguna 0m0.872s
sys 0m0.760s
EDIT 2: Konsep yang sama, solusi yang lebih baik digunakan find
untuk melihat waktu akses (digunakan %T
dengan yang pertama printf
untuk waktu modifikasi atau %C
untuk perubahan status sebagai gantinya).
find . -wholename "*" -type f -printf "%AY%Am%Ad %h/%f\n" | awk 'BEGIN {cont=0; oldd=strftime("%Y%m%d"); } { if ($1 < oldd) { oldd=$1; oldf=$2; for(i=3; i<=NF; i++) oldf=oldf " " $i; }; count++; } END { print "Oldest date: ", oldd, "\nFile:", oldf, "\nTotal compared: ", count}'
EDIT 3: Perintah di bawah ini menggunakan waktu modifikasi dan juga mencetak progres tambahan saat menemukan file yang lebih lama dan lebih lama, yang berguna ketika Anda memiliki cap waktu yang salah (seperti 1970-01-01):
find . -wholename "*" -type f -printf "%TY%Tm%Td %h/%f\n" | awk 'BEGIN {cont=0; oldd=strftime("%Y%m%d"); } { if ($1 < oldd) { oldd=$1; oldf=$2; for(i=3; i<=NF; i++) oldf=oldf " " $i; print oldd " " oldf; }; count++; } END { print "Oldest date: ", oldd, "\nFile:", oldf, "\nTotal compared: ", count}'
ls
buruk untuk scripting karena outputnya tidak dimaksudkan untuk mesin, format output bervariasi di seluruh implementasi. Seperti yang sudah Anda nyatakan find
bagus untuk scripting tetapi mungkin juga bagus untuk menambahkan info itu sebelum menceritakan ls
solusi.
Silakan gunakan ls - halaman manual memberi tahu Anda cara memesan direktori.
ls -clt | head -n 2
-N 2 adalah sehingga Anda tidak mendapatkan "total" di output. Jika Anda hanya menginginkan nama file.
ls -t | head -n 1
Dan jika Anda membutuhkan daftar dalam urutan normal (mendapatkan file terbaru)
ls -tr | head -n 1
Jauh lebih mudah daripada menggunakan find, jauh lebih cepat, dan lebih kuat - tidak perlu khawatir tentang format penamaan file. Ini seharusnya bekerja pada hampir semua sistem juga.
find ! -type d -printf "%T@ %p\n" | sort -n | head -n1
sort -n
.
Tampaknya oleh "tertua" kebanyakan orang berasumsi bahwa Anda berarti "waktu modifikasi tertua." Itu mungkin diperbaiki, menurut interpretasi paling ketat dari "tertua", tetapi jika Anda menginginkan yang memiliki waktu akses terlama , saya akan mengubah jawaban terbaik sebagai berikut:
find -type f -printf '%A+ %p\n' | sort | head -n 1
Perhatikan %A+
.
set $(find /search/dirname -type f -printf '%T+ %h/%f\n' | sort | head -n 1) && echo $2
find ./search/dirname -type f -printf '%T+ %h/%f\n'
mencetak tanggal dan nama file dalam dua kolom.sort | head -n1
menjaga garis yang sesuai dengan file terlama.echo $2
menampilkan kolom kedua, yaitu nama file.
find -type f -printf '%T+ %p\n' | sort | head -1