Bir dizin ağacındaki en eski dosyayı nasıl bulabilirim


Yanıtlar:


72

Bu çalışır (Daniel Andersson'un önerisini içerecek şekilde güncellenmiştir):

find -type f -printf '%T+ %p\n' | sort | head -n 1

8
Daha az yazarak:find -type f -printf '%T+ %p\n' | sort | head -1
Daniel Andersson

1
Boş alan oluyorum çünkü ilk satırım findboş. Çünkü dosya adım newline içeriyor.
皞 皞

1
Bunun oluşturulan veya değiştirilme tarihini kullanıp kullanmadığını sorabilir miyim?
MrMesees

1
Linux, dosya oluşturma tarihini hiçbir yerde kaydetmez [*]. Bu değişiklik tarihini kullanır. [*] bu aslında doğru değil; ext4 inode oluşturma tarihini saklar, ancak herhangi bir sistem çağrısı yoluyla açığa
çıkmaz

11

Bu biraz daha taşınabilir ve GNU finduzantısına bağlı olmadığından -printfBSD / OS X üzerinde de çalışıyor:

find . -type f -print0 | xargs -0 ls -ltr | head -n 1

Burada sadece olumsuz boyutuna biraz sınırlı olmasıdır ARG_MAX( gerekir en yeni çekirdekleri için dikkate alınmaz). Bu nedenle, getconf ARG_MAXdöndürülen karakterlerden daha fazlası varsa (sistemimde 262.144), size doğru sonucu vermez. Aynı zamanda POSIX uyumlu olduğu için değil -print0ve xargs -0değil.

Bu soruna daha fazla çözüm burada özetlenmiştir: En son (en yeni, en eski, en eski) dosyayı bir dizinde nasıl bulabilirim? - Greg'in Wiki'si


Bu da işe yarıyor ama aynı zamanda xargs: ls: terminated by signal 13yan etki olarak da bir hata veriyor . Sanırım bu SIGPIPE. Sort'ın çıkışını benim çözümüme göre yönlendirirken neden benzer bir hata alamadığımı bilmiyorum.
Marius Gedminas

Sürümünüz de bellekten yazmak daha kolaydır. :-)
Marius Gedminas,

Evet, bu kırık bir boru. Tüm bu komutların hem GNU hem de BSD versiyonlarında bunu anlamadım, ancak headbir satırı okuduktan sonra çıkan ve bu nedenle boruyu "kıran" komuttur. Hatayı almazsınız, çünkü sortşikayetçi görünmüyor, ancak lsdiğer durumda.
slhck

4
Bu, birden fazla kez xargsçağırması gereken çok fazla dosya adı varsa kırılır ls. Bu durumda, bu çoklu çağrıların sıralanan çıktıları birleştirilmeleri gerektiğinde birleştirilir.
Nicole Hamilton

2
Bunun dosya adlarının hiç boşluk içermediğini varsayan bir komut dosyası göndermekten daha kötü olduğunu düşünüyorum. Çoğu zaman, bunlar işe yarayacak çünkü dosya isimlerinin boşlukları yok. Ve başarısız olduklarında hata alırsın. Ancak bunun gerçek durumlarda işe yaraması pek mümkün değildir ve başarısızlık keşfedilmeyecektir. Adil değil yeterince büyük herhangi bir dizin ağacında üzerinde olduğunu yapabilecekleriniz lso ve en eski dosyayı eyeball, çözüm muhtemelen olacaktır neden komut satırı uzunluğu sınırı aşıldı lsbirden çok kez çağırılacak. Yanlış cevap alırsınız ama asla bilemeyeceksiniz.
Nicole Hamilton

11

Aşağıdaki komutların, her tür garip dosya adıyla çalışması garanti edilir:

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/[^ ]* //')"

\0Satır besleme karakteri yerine ( ) boş bir bayt ( ) kullanmak \n, dosya adlarından birinin satır besleme karakteri içermesi durumunda bulma çıktısının yine de anlaşılabilir olmasını sağlar.

-zAnahtar sıralama ve grep hem sonu hattı karakterleri olarak sadece boş bayt yorumlamak yapar. Kafa için böyle bir anahtar olmadığından grep -m 1bunun yerine kullanırız (sadece bir olay).

Komutlar yürütme süresi ile sıralanır (makinemde ölçülür).

  • İlk komut en yavaş olacaktır, çünkü her dosyanın ilk zamanını önce insan tarafından okunabilir bir formata dönüştürmek ve sonra bu dizeleri sıralamak zorundadır. Cat'e borulama, çıktının renklenmesini önler.

  • İkinci komut biraz daha hızlı. Hala tarih dönüşümünü gerçekleştirirken, sort -nUnix çağının biraz daha hızlı olması nedeniyle geçen saniyeleri sayısal olarak sıralamak ( ). sed, Unix döneminden bu yana saniye siler.

  • Son komut hiçbir şekilde dönüşüm yapmaz ve ilk ikisinden çok daha hızlı olmalıdır. Find komutunun kendisi en eski dosyanın mtime değerini göstermez, bu nedenle stat gereklidir.

İlgili adam sayfaları: bul - grep - sed - sort - stat


5

Kabul edilen cevap ve buradaki diğerleri işi yapsa da, çok büyük bir ağacınız varsa, hepsi bütün dosyaları sıralar.

Daha iyi olur, onları sıralamak ve sıralamak zorunda kalmadan en eskisini takip edebilseydik.

Bu yüzden bu alternatif çözümü buldum:

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

Umarım, soru biraz eski olsa bile, herhangi bir yardımı olabilir.


Düzen 1: bu değişiklikler dosya ve dizinleri boşluk içeren ayrıştırmaya izin verir. Kökünden yayınlamak /ve şimdiye kadarki en eski dosyayı bulmak için yeterince hızlı .

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

Komut açıkladı:

  • ls -lRU - time-style = long-iso "$ PWD" / *, tüm dosyaları (*), uzun formatı (l), yinelemeli (R), hızlı olacak şekilde sıralama yapmadan (U) ve awk olarak sıralar.
  • Awk ardından sayacı sıfırlayarak BEGIN (bu soruya isteğe bağlı) ve bugün olacak en eski olanı ayarlayarak, YearMonthDay'i biçimlendirin.
  • İlk önce ana döngü
    • 6. alanı, tarihi, Yıl-Ay-Gün biçimini alın ve Yıl-Ay Gün olarak değiştirin (eğer bu şekilde çıkmazsa, ince ayar yapmanız gerekebilir).
    • Özyinelemeyi kullanarak, tüm dizinler için / directory / here: şeklinde başlık satırları olacaktır. Bu satırı pat değişkenine al. (son ":" ifadesini "/" ile değiştirerek). Ve başlık satırını geçerli bir dosya satırı olarak kullanmaktan kaçınmak için 6 $ 'ı hiçbir şeye ayarlamaz.
    • $ 6 alanı geçerli bir sayıya sahipse, bir tarih. Eski tarih oldd ile karşılaştırın.
    • Daha yaşlı mı Sonra eski tarih oldd ve eski dosya adı oldf için yeni değerleri kaydedin. Btw, oldf sadece 8 alan değil, 8 ila sonuna kadar. Bu yüzden 8'den NF'ye (son) kadar birleştirmek için bir döngü.
    • Biri ile sayıları ilerlet
    • Sonucu yazdırarak SON

Çalıştırılıyor:

~ $ time ls -lRU "$ PWD" / * | awk vs.

En eski tarih: 19691231

Dosya: /home/.../.../backupold/.../EXAMPLES/how-to-program.txt

Toplam Karşılaştırması: 111438

gerçek 0m1.135'ler

kullanıcı 0m0.872s

Sys 0m0.760'lar


DÜZENLEME 2: Aynı kavramı kullanılarak daha iyi bir çözüm findbakmak için erişim süre (kullanmak %Tilk ile printfiçin modifikasyon zaman ya %Ciçin durum değişikliği yerine).

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

DÜZENLEME 3: feryat komutu değişiklik zamanını kullanır ve aynı zamanda daha eski ve daha eski dosyaları bulduğu için artan ilerlemeyi de yazdırır;

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

Hala boşluk içeren dosyaları kabul etmek için tweeking gerekiyor. Bunu yakında yaparım.
Dr Beco

Sanırım ls 'i boşluklu dosyalar için ayrıştırmak iyi bir fikir değil. Belki Bul kullanarak.
Dr Beco,

Sadece "/" ağacında çalıştır. Harcanan zaman: Toplam karşılaştırıldı: 585744 gerçek 2m14.017s kullanıcı 0m8.181s sys 0m8.473s
Dr Beco

Kullanılması lsçıkış makineleri için verilmemiştir olarak komut dosyası için kötüdür, çıkış biçimlendirme uygulamaları üzerinden değişir. Daha önce belirttiğiniz gibi find, komut dosyası yazmak için iyi, ancak lsçözümleri anlatmadan önce bu bilgileri eklemek de iyi olabilir .
Sampo Sarrala

4

Lütfen ls kullanın - man sayfası size dizinin nasıl sipariş edileceğini söyler.

ls -clt | head -n 2

-N 2, çıktıda "toplam" alamıyorsunuz. Sadece dosyanın adını istiyorsanız.

ls -t | head -n 1

Ve normal sırayla listeye ihtiyacınız varsa (en yeni dosyayı almak)

ls -tr | head -n 1

Bulmayı kullanmaktan çok daha kolay, çok daha hızlı ve daha sağlam - dosya adlandırma biçimleri konusunda endişelenmenize gerek yok. Neredeyse tüm sistemlerde de çalışması gerekiyor.


6
Bu sadece dosyalar tek bir dizindeyse çalışır, sorum ise bir dizin ağacı ile ilgiliyken.
Marius Gedminas

2
find ! -type d -printf "%T@ %p\n" | sort -n | head -n1

9 Eylül 2001'den daha eski dosyalar (Unix döneminden bu yana 1000000000 saniye) varsa, bu düzgün çalışmaz. Sayısal sıralamayı etkinleştirmek için kullanın sort -n.
Dennis,

Bu bana dosyayı bulmanıza yardımcı olur, ancak ikinci bir komutu çalıştırmadan kaç yaşında olduğunu görmek çok zor :)
Marius Gedminas

0

Görünüşe göre çoğu insan "en eski" zamanını "kastettiğini" varsayıyor. Bu, "en eski" nin en katı yorumuna göre düzeltilmiştir, ancak en eski erişim zamanına sahip olanı istemeniz durumunda, en iyi cevabı değiştiririm:

find -type f -printf '%A+ %p\n' | sort | head -n 1

Dikkat edin %A+.


-1
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' tarihleri ​​ve dosya adlarını iki sütuna yazdırır.
  • sort | head -n1 en eski dosyaya karşılık gelen satırı tutar.
  • echo $2 ikinci sütunu, yani dosya adını görüntüler.

1
Süper Kullanıcıya Hoşgeldiniz! Bu soruyu cevaplayabilse de, neden böyle olduğunu açıklayabilirseniz daha iyi bir cevap olabilir .
DavidPostill

1
Ayrıca, birkaç kişi daha önceki (aynı) silinen yanıtın açıklamasını istedi.
DavidPostill

Cevaplaması zor olan ne? Bulun ./search/dirname -type f -printf '% T +% h /% f \ n' | sıralama | head -n 1 Dosyanın zaman ve yolu olarak iki sütun gösterir. İlk sütunu kaldırmak gerekir. Set ve echo 2 $ 'ı kullanma
Dima

1
Diğer kullanıcıların istediği gibi sadece bir komut satırı yapıştırmak yerine açıklamalar yapmalısınız.
Ob1lan

1
Kabul edilen cevaptan sonra bunun farkı nedir?
Ramhound
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.