Bir dizin ağacındaki en eski dosyayı bulmak için bir kabuk kabuğu arıyorum.
Bir dizin ağacındaki en eski dosyayı bulmak için bir kabuk kabuğu arıyorum.
Yanıtlar:
Bu çalışır (Daniel Andersson'un önerisini içerecek şekilde güncellenmiştir):
find -type f -printf '%T+ %p\n' | sort | head -n 1
find
boş. Çünkü dosya adım newline içeriyor.
Bu biraz daha taşınabilir ve GNU find
uzantısına bağlı olmadığından -printf
BSD / 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_MAX
dö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 -print0
ve xargs -0
değ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
xargs: ls: terminated by signal 13
yan 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.
head
bir 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 ls
diğer durumda.
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.
ls
o ve en eski dosyayı eyeball, çözüm muhtemelen olacaktır neden komut satırı uzunluğu sınırı aşıldı ls
birden çok kez çağırılacak. Yanlış cevap alırsınız ama asla bilemeyeceksiniz.
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/[^ ]* //')"
\0
Satı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.
-z
Anahtar 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 1
bunun 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 -n
Unix ç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.
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ı:
Ç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 find
bakmak için erişim süre (kullanmak %T
ilk ile printf
için modifikasyon zaman ya %C
iç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}'
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 .
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.
find ! -type d -printf "%T@ %p\n" | sort -n | head -n1
sort -n
.
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+
.
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.
find -type f -printf '%T+ %p\n' | sort | head -1