Unix / Linux ค้นหาและจัดเรียงตามวันที่แก้ไข


138

ฉันจะทำแบบง่าย ๆfindซึ่งจะเรียงลำดับผลลัพธ์โดยการแก้ไขล่าสุดได้อย่างไร

นี่คือปัจจุบันที่findฉันใช้ (ฉันกำลังหลบหนีเชลล์ใน PHP ดังนั้นนี่คือเหตุผลสำหรับตัวแปร):

find '$dir' -name '$str'\* -print | head -10

ฉันจะให้คำสั่งนี้ค้นหาโดยแก้ไขล่าสุดได้อย่างไร (หมายเหตุฉันไม่ต้องการให้เรียงลำดับ 'หลัง' การค้นหา แต่ควรค้นหาผลลัพธ์ตามสิ่งที่ได้รับการแก้ไขล่าสุด)


github.com/shadkam/recentmostจะทำสิ่งที่ต้องการ - แต่เราต้องการสร้างมันขึ้นมา
user3392225

คำตอบ:


153

ใช้สิ่งนี้:

find . -printf "%T@ %Tc %p\n" | sort -n

printfการโต้แย้งจากman find:

  • %Tk: kการปรับเปลี่ยนเวลาของไฟล์ที่ผ่านมาในรูปแบบที่กำหนดโดย

  • @: วินาทีตั้งแต่ 1 มกราคม 1970, 00:00 GMT โดยมีส่วนที่เป็นเศษส่วน

  • c: วันที่และเวลาของ locale (Sat Nov 04 12:02:33 EST 1989)

  • %p: ชื่อไฟล์


5
+1 มีประโยชน์มาก, คำตอบแรกนี้ฉันได้พบกับอ่านได้ประโยชน์ส่งออก / วัน
เจค N

เชื่อถือได้มากที่สุด (และง่ายมาก) เมื่อเวลาได้รับการเรียงลำดับตัวเลข
อำนาจกุมภ์

1
ฉันมีนามแฝงนี้สำหรับการค้นหาไฟล์ล่าสุดในของฉัน~/.zshrc: fr () { find ./ -iname "*"$@"*" -printf "%T@ %Td-%Tb-%TY %Tk:%TM %p\n" | sort -n | cut -d " " -f 2- | grep -i "$@" ; }มันจะค้นหาไฟล์ทั้งหมดที่มีรูปแบบของการโต้แย้งครั้งแรกที่ส่งผ่านไปยังคำสั่ง ( fr <pattern>) และเรียงลำดับพวกเขาด้วยล่าสุดล่าสุด
joelostblom

มันยอดเยี่ยมมาก !!! หากต้องการใช้กับ symlink ให้ใช้find -L ...
Varun Chandak

1
คุณอาจต้องการใช้ssedเพื่อกำจัดเศษส่วนส่วนวินาทีและใช้ ISO8601 เป็น @PeterMortensen แสดง:find . -type f -printf "%TY-%Tm-%TdT%TT %p\n" | sort -r | ssed -R 's/^([^.]+)\.\d+ (.*)$/\1 \2/'
Ludovic Kuty

83

วิธีที่ง่ายที่สุดคือการใช้ zsh ขอบคุณมันบ่น glob

print -lr -- $dir/**/$str*(om[1,10])

หากคุณมี GNU ค้นหาให้พิมพ์เวลาแก้ไขไฟล์และเรียงลำดับตามนั้น

find -type f -printf '%T@ %p\0' |
sort -zk 1nr |
sed -z 's/^[^ ]* //' | tr '\0' '\n' | head -n 10

หากคุณมี GNU ค้นหา แต่ไม่ใช่ยูทิลิตี้ GNU อื่นให้ใช้การขึ้นบรรทัดใหม่เป็นตัวคั่นแทนค่า null คุณจะสูญเสียการสนับสนุนชื่อไฟล์ที่มีการขึ้นบรรทัดใหม่

find -type f -printf '%T@ %p\n' |
sort -k 1nr |
sed 's/^[^ ]* //' | head -n 10

หากคุณมี Perl (ที่นี่ฉันจะถือว่าไม่มีบรรทัดใหม่ในชื่อไฟล์):

find . -type f -print |
perl -l -ne '
    $_{$_} = -M;  # store file age (mtime - now)
    END {
        $,="\n";
        @sorted = sort {$_{$a} <=> $_{$b}} keys %_;  # sort by increasing age
        print @sorted[0..9];
    }'

หากคุณมี Python (สมมติว่าไม่มีบรรทัดใหม่ในชื่อไฟล์):

find . -type f -print |
python -c 'import os, sys; times = {}
for f in sys.stdin.readlines(): f = f[0:-1]; times[f] = os.stat(f).st_mtime
for f in (sorted(times.iterkeys(), key=lambda f:times[f], reverse=True))[:10]: print f'

อาจมีวิธีการทำเช่นเดียวกันใน PHP แต่ฉันไม่ทราบ

หากคุณต้องการทำงานกับเครื่องมือ POSIX เท่านั้นมันค่อนข้างซับซ้อนกว่า ดูวิธีแสดงรายการไฟล์ที่เรียงลำดับตามวันที่แก้ไขซ้ำ (ไม่มีคำสั่งสถิติให้ใช้!) (การแปล 10 รายการแรกเป็นส่วนที่ง่าย)


ผมคิดว่าfindรุ่นแสดงไฟล์ที่เก่าแก่ที่สุดและที่คุณจำเป็นต้องเพิ่มตัวเลือกในการ-r sort
Quentin Pradet

sed ของฉันบอกว่าไม่มีตัวเลือก -z
Kef Schecter

@KefSchecter จากนั้นใช้การขึ้นบรรทัดใหม่เป็นตัวคั่น แต่คุณจะสูญเสียการสนับสนุนบรรทัดใหม่ในชื่อไฟล์
Gilles

ด้านบนสำหรับ python2 หากคุณมี python3 เพียงบางอย่างการเปลี่ยนแปลงเล็กน้อย: python3 -c 'import os, sys; times = {} สำหรับ f ใน sys.stdin.readlines (): f = f [0: -1]; ครั้ง [f] = os.stat (f) .st_mtime สำหรับ f in (เรียงลำดับ (times.keys (), key = lambda f: คูณ [f], reverse = True)) [: 10]: print (f); '
Neil McGill

40

คุณไม่จำเป็นต้อง PHP หรือ Python เพียงแค่ls :

man ls:
-t     sort by modification time
-r,    reverse order while sorting (--reverse )
-1     list one file per line

find /wherever/your/files/hide -type f -exec ls -1rt "{}" +;

หากคำสั่ง * ออกจากพร้อมสถานะความล้มเหลว (เช่นรายการอาร์กิวเมนต์ยาวเกินไป ) คุณสามารถทำซ้ำได้ด้วย find ถอดความจาก: ความยาวสูงสุดของการขัดแย้งสำหรับกระบวนการใหม่

  • find . -print0|xargs -0 command (เพิ่มประสิทธิภาพความเร็วหากการค้นหาไม่ได้ใช้ "-exec +" แต่รู้ว่า "-print0")
  • find . -print|xargs command (ถ้าไม่มีช่องว่างในการโต้แย้ง)

หากส่วนหลักของข้อโต้แย้งประกอบด้วยเส้นทางยาวสัมบูรณ์หรือเส้นทางสัมพัทธ์ลองย้ายการกระทำของคุณไปยังไดเรกทอรี: cd /directory/with/long/path; command *และการแก้ไขด่วนอื่นอาจตรงกับอาร์กิวเมนต์ที่น้อยลง:command [a-e]*; command [f-m]*; ...


1
หากมีไฟล์จำนวนมากสิ่งนี้จะล้มเหลวด้วย 'รายการอาร์กิวเมนต์ยาวเกินไป' ใน ls
occulus

1
นั่นเป็นความจริง แต่ฉันเชื่อว่าคำถามคือ "ฉันจะหาแบบง่าย ๆ ได้อย่างไร ... "
ЯрославРахматуллин

2
LS ไม่ได้พูดชื่อไฟล์ในทาง xargs สามารถเข้าใจ (ไม่ -0 ตัวเลือกและรูปแบบใบเสนอราคาต่างๆมีไม่เพียงพอ)
Tobu

10

คุณต้องการเพียงls

คุณสามารถทำfind /wherever/your/files/hide -type f -exec ls -1rt "{}" +;ตามที่ระบุไว้ข้างต้น

หรือ

ls -1rt `find /wherever/your/file/hides -type f`

2
หากมีไฟล์จำนวนมากสิ่งนี้จะล้มเหลวด้วย 'รายการอาร์กิวเมนต์ยาวเกินไป' ใน ls อาจลองใช้ xargs อีกครั้ง?
occulus

2
แต่ถ้าxargsโทรlsหลายครั้งการเรียงลำดับจะไม่ทำงาน
Aaron D. Marasco

สิ่งนี้ล้มเหลวสำหรับไฟล์ที่มีช่องว่างในชื่อ คำแนะนำใด ๆ?
user74094

เพิ่งสะดุดกับคำตอบนี้และมันเป็นสิ่งที่ฉันต้องการในสถานการณ์ที่คล้ายกัน คำถาม: +;ท้ายที่สุดทำอะไร ดูเหมือนว่าจะให้ผลลัพธ์เดียวกันโดยไม่ต้อง;อย่างไรก็ตามมันไม่ทำงานโดยไม่ต้อง+?
RocketNuts

นี่เป็นเช่นเดียวกับคำตอบอื่นที่โพสต์เมื่อ 8 เดือนก่อนยกเว้นส่วนที่เกี่ยวกับการใช้ "ls -1rt` find … `" ซึ่งเสีย
Clément

7

การขยายคำตอบของ user195696 :

find . -type f -printf "%T@\t%Tc %6k KiB %p\n" | sort -n | cut -f 2-

สำหรับแต่ละไฟล์ไฟล์แรกจะส่งออกการประทับเวลาแบบตัวเลข (สำหรับการเรียงลำดับตามด้วยการจัดระเบียบ\t) จากนั้นตามเวลาที่มนุษย์อ่านได้จากนั้นขนาดไฟล์ (น่าเสียดายfindที่-printfไม่สามารถทำได้ใน mebibytes เพียง kibibytes) จากนั้นชื่อไฟล์ เส้นทาง.

จากนั้นsort -nเรียงลำดับตามฟิลด์ตัวเลขแรก

จากนั้นcutกำจัดฟิลด์ตัวเลขแรกที่ผู้ใช้ไม่สนใจ (พิมพ์ฟิลด์ที่สองเป็นต้นไป) ตัวคั่นฟิลด์เริ่มต้นคือ\tหรือการจัดตาราง

ตัวอย่างผลลัพธ์:

Thu 06 Feb 2014 04:49:14 PM EST     64 KiB ./057_h2_f7_10/h2_f7_10.class
Fri 07 Feb 2014 02:08:30 AM EST 7962976 KiB ./056_h2_f7_400/h2__rh_4e-4.mph
Fri 07 Feb 2014 02:23:24 AM EST 7962976 KiB ./056_h2_f7_400/h2_f7_400_out_Model.mph
Fri 07 Feb 2014 02:23:24 AM EST      0 KiB ./056_h2_f7_400/h2_f7_400_out.mph.status
Fri 07 Feb 2014 02:23:24 AM EST     64 KiB ./056_h2_f7_400/1579678.out
Fri 07 Feb 2014 03:47:31 AM EST 8132224 KiB ./057_h2_f7_10/h2__rh_1e-5.mph
Fri 07 Feb 2014 04:00:49 AM EST 8132224 KiB ./057_h2_f7_10/h2_f7_10_out_Model.mph
Fri 07 Feb 2014 04:00:49 AM EST      0 KiB ./057_h2_f7_10/h2_f7_10_out.mph.status
Fri 07 Feb 2014 04:00:49 AM EST     64 KiB ./057_h2_f7_10/1579679.out
Fri 07 Feb 2014 09:47:18 AM EST   9280 KiB ./056_h2_f7_400/h2__rh_4e-4.mat
Fri 07 Feb 2014 10:51:23 AM EST   9728 KiB ./018_bidomain/h2_plain__rh_1e-5.mat
Fri 07 Feb 2014 10:58:33 AM EST   9568 KiB ./057_h2_f7_10/h2__rh_1e-5.mat
Fri 07 Feb 2014 05:05:38 PM EST     64 KiB ./058_h2_f7_stationary/h2_f7_stationary.java
Fri 07 Feb 2014 06:06:29 PM EST     32 KiB ./058_h2_f7_stationary/slurm.slurm
Sat 08 Feb 2014 03:42:07 AM EST      0 KiB ./058_h2_f7_stationary/1581061.err
Sat 08 Feb 2014 03:42:14 AM EST     64 KiB ./058_h2_f7_stationary/h2_f7_stationary.class
Sat 08 Feb 2014 03:58:28 AM EST  70016 KiB ./058_h2_f7_stationary/h2s__rh_1e-5.mph
Sat 08 Feb 2014 04:12:40 AM EST  70304 KiB ./058_h2_f7_stationary/h2s__rh_4e-4.mph
Sat 08 Feb 2014 04:12:53 AM EST  70304 KiB ./058_h2_f7_stationary/h2_f7_stationary_out_Model.mph
Sat 08 Feb 2014 04:12:53 AM EST      0 KiB ./058_h2_f7_stationary/h2_f7_stationary_out.mph.status
Sat 08 Feb 2014 04:12:53 AM EST     32 KiB ./058_h2_f7_stationary/1581061.out
Mon 10 Feb 2014 11:40:54 AM EST    224 KiB ./058_h2_f7_stationary/h2s__rh_4e-4.mat
Mon 10 Feb 2014 11:42:32 AM EST    224 KiB ./058_h2_f7_stationary/h2s__rh_1e-5.mat
Mon 10 Feb 2014 11:50:08 AM EST     32 KiB ./plot_grid.m

ฉันจงใจทำให้ขนาดฟิลด์ของตัวละคร 6 ตัวเพราะถ้าทำให้มันยาวขึ้นมันจะยากที่จะแยกแยะว่าไฟล์มีขนาดใหญ่เพียงใด ด้วยวิธีนี้ไฟล์ที่มีขนาดใหญ่กว่า 1e6 KiB ยื่นออก: โดย 1 ถ่านหมายถึง 1-9 GB โดย 2 ตัวอักษรหมายถึง 10-99 GB เป็นต้น


แก้ไข: นี่เป็นอีกเวอร์ชั่นหนึ่ง (เนื่องจากfind . -printf "%Tc"ขัดข้องใน MinGW / MSYS):

find . -type f -printf "%T@\t%p\n" | sort -n | cut -f 2- | xargs -I{} ls -Glath --si {}

ให้ผลลัพธ์เช่น:

-rw-r--r-- 1 es 23K Jul 10  2010 ./laptop_0000071.jpg
-rw-r--r-- 1 es 43M Jul 29 19:19 ./work.xcf
-rw-r--r-- 1 es 87K Jul 29 20:11 ./patent_lamps/US Patent 274427 Maxim Lamp Holder.jpg
-rw-r--r-- 1 es 151K Jul 29 20:12 ./patent_lamps/Edison screw-in socket.png
-rw-r--r-- 1 es 50K Jul 29 20:13 ./patent_lamps/1157 Lamp.jpg
-rw-r--r-- 1 es 38K Jul 29 20:14 ./patent_lamps/US06919684-20050719-D00001.png

ที่ไหน:

  • -I{}ทำให้เกิด{}การแทนที่ด้วยการโต้แย้งและการขึ้นบรรทัดใหม่เป็นตัวแยกอาร์กิวเมนต์ (หมายเหตุช่องว่างในชื่อไฟล์ด้านบน)

  • ls -G ไม่แสดงการพิมพ์ชื่อกลุ่ม (เปลืองพื้นที่)

  • ls -h --siสร้างขนาดไฟล์ที่มนุษย์อ่านได้ (ถูกต้องมากขึ้น--si)

  • ls -t เรียงลำดับตามเวลาซึ่งไม่เกี่ยวข้องกับที่นี่ แต่นั่นคือสิ่งที่ฉันมักจะใช้


1
หมายเหตุ: หากต้องการจัดเรียงตามขนาดไฟล์แทนเพียงแค่แทนที่T@ด้วยsในคำสั่งด้านบน
Evgeni Sergeev

3

ตัวแปร OS X ของคำตอบของ @ user195696:

  1. ด้วยการประทับเวลา:

    find . -type f -exec stat -f "%Sm %N" -t "%Y%y%m%d%H%M" {} \; | sort -r
    
  2. ไม่มีการประทับเวลา:

    find . -type f -exec stat -f "%Sm %N" -t "%Y%y%m%d%H%M" {} \; | sort -r | awk -F' ' '{ print substr($0, length($1) + 2) }'
    

2

ฉันพบว่าสิ่งนี้ทำงานบน Mac OS X (และทั่วไปพอที่จะทำงานกับ Unixen อื่น ๆ ได้เช่นกัน):

find . -type f -ls | awk '{print $(NF-3), $(NF-2), $(NF-1), $NF}' | sort

2
น่าเศร้าที่พิมพ์ชื่อเดือนที่มีการแปลในการตั้งค่าโครเอเชียของฉันทำให้การเรียงลำดับไม่ถูกต้อง
Ivan Vučica

คำตอบของ user195696ใช้ได้กับการตั้งค่าภาษาโครเอเชีย (และอื่น ๆ )
Peter Mortensen

1

หากการfindเลือกของคุณง่ายมากคุณอาจสามารถทำได้โดยไม่ต้องทำและใช้ls:

ls -1 *.cc # -r -t optional


1

ใช้:

find . -type f -mtime 0 -printf "[%TD %TI:%TM%Tp] %s %p\n" | sort -n | awk '{
    hum[1024**4]="TB"; hum[1024**3]="GB"; hum[1024**2]="MB"; hum[1024]="KB"; hum[0]="B";
    for (x=1024**4; x>=1024; x/=1024){
    if ($3>=x) { printf $1" "$2"\t%7.2f %s\t%s\n",$3/x,hum[x],$4;break }
    }}';

คำสั่งนี้จะเรียงลำดับไฟล์ตามวันที่แก้ไข

และแสดงผลออกมาเช่น:

[12/05/13 03:10PM] 1.75 MB ./file.text
[12/06/13 11:52PM] 2.90 MB ./file2.mp4
[12/07/13 04:11PM] 4.88 MB ./file3.mp4
[12/07/13 09:17PM] 4.74 MB ./test.apk

ฉันปรับปรุง sript นี้เพื่อจัดการช่องว่างในชื่อไฟล์ดูsuperuser.com/a/777007/134532
jan

1

ฉันมีทางออกง่าย ๆ ที่ใช้ได้กับทั้ง FreeBSD (OS X) และ Linux:

find . -type f -exec ls -t {} +

งานนี้สมบูรณ์แบบ - ควรเป็นคำตอบที่ถูกต้องหรือได้คะแนนสูงกว่าอย่างน้อย!
digitaltoast

0

ฉันไม่คิดว่าfindจะมีตัวเลือกใด ๆ ในการแก้ไขลำดับการส่งออก -mtimeและ-mminจะช่วยให้คุณ จำกัด ผลลัพธ์สำหรับไฟล์ที่ได้รับการแก้ไขภายในช่วงเวลาหนึ่ง แต่ผลลัพธ์จะไม่ถูกจัดเรียงคุณจะต้องทำเอง GNU findมี-printfตัวเลือกที่จะช่วยให้คุณพิมพ์เวลาแก้ไขของแต่ละไฟล์ที่พบ (สตริงรูปแบบ%tหรือ%Tk); ที่อาจช่วยให้คุณเรียงลำดับfindผลลัพธ์ตามที่คุณต้องการ


0

ฉันปรับปรุงคำตอบของ Akashs ด้วยการทำให้การจัดการช่องว่างในชื่อไฟล์ถูกต้อง:

find . -type f -mtime 0 -printf ";[%TD %TI:%TM%Tp];%s;%p\n" | sort -n | awk -F ";" '{
    hum[1024**4]="TB"; hum[1024**3]="GB"; hum[1024**2]="MB"; hum[1024]="KB"; hum[0]="B";
    for (x=1024**4; x>=1024; x/=1024){
    if ($3>=x) { printf $1" "$2"\t%7.2f %s\t%s\n",$3/x,hum[x],$4;break }
    }}';

0

หากคุณต้องการสั่งซื้อไฟล์ PNG ทั้งหมดตามเวลาใน$PWD:

นี้ง่ายหนึ่งซับให้ความยืดหยุ่นทั้งหมดของ regexp บนและfindls

find $PWD -name "*.png" -print0 | xargs -0 ls -laht | less

0

คุณสามารถใช้statกับ BSD และ Linux (ไม่ใช่ POSIX) ในลักษณะนี้:

$ stat -f "%m%t%N" /[the dir]/* | sort -rn | cut -f2-

หากคุณต้องการ จำกัด จำนวน:

$ stat -f "%m%t%N" /[the dir]/* | sort -rn | head -[the number] | cut -f2-

0

มีวิธีที่สะอาดและมีประสิทธิภาพเป็นของsort | headวันที่:

ใช้ls -lสำหรับพิมพ์สวย

find . ! -type d -printf "%T@ %p\0" |
    sort -zrn |
    head -zn 10 |
    sed -z 's/^[0-9.]\+ //' |
    xargs -0 ls -lt

ในฐานะที่เป็นฟังก์ชั่น :

findByDate() {
    local humansize=''
    [ "$1" = "-h" ] && humansize='h' && shift
    find . ${2:-! -type d} -printf "%T@ %p\0" |
        sort -zrn |
        head -zn ${1:--0} |
        sed -z 's/^[0-9.]\+ //' |
        xargs -0 ls -dlt${humansize}
}

สิ่งนี้ทำได้ด้วยการโต้แย้งหนึ่งหรือสองครั้งหรือแม้กระทั่งโดยไม่

Usage: findByDate [-h] [lines] [find options]

ตัวอย่าง:

findByDate

จะแสดงรายการไดเรกทอรีที่ไม่ใช่ทั้งหมดเรียงตามวันที่ หมายเหตุ:

แม้บนระบบไฟล์ขนาดใหญ่เนื่องจากxargs รายการที่เรียงแล้วได้รับลำดับไฟล์จะยังคงถูกต้องแม้ว่าlsจะต้องรันหลายครั้ง

findByDate -h 12

จะแสดงรายการ 12 ไดเรกทอรีล่าสุดที่ไม่เรียงลำดับตามวันที่โดยมีขนาดพิมพ์ในรูปแบบที่มนุษย์อ่านได้

findByDate 42 '-type l'

จะแสดงรายการลิงก์ระลึกล่าสุดอีก 42 รายการ

findByDate -0 '( -type l -o -type b -o -type s -o -type c )'

จะแสดงรายการ symlink อุปกรณ์บล็อกซ็อกเก็ตและอุปกรณ์อักขระทั้งหมดเรียงตามวันที่

คำสั่งอินเวอร์

แทนที่headด้วยtailและเปลี่ยนสวิตช์ของsortและls:

findByDate() {
    local humansize=''
    [ "$1" = "-h" ] && humansize='h' && shift
    find . ${2:-! -type d} -printf "%T@ %p\0" |
        sort -zn |
        tail -zn ${1:-+0} |
        sed -z 's/^[0-9.]\+ //' |
        xargs -0 ls -dltr${humansize}
}

ฟังก์ชั่นเดียวกันการใช้งานเดียวกัน:

Usage: findByDate [-h] [lines] [find options]

-1

หากคุณต้องการได้รับเส้นทางเต็มของแต่ละรายการคุณสามารถเขียนแบบนี้

 find FIND_ROOT -maxdepth 1 -type f -printf "%T@ %p\n" | sort -nr | head -10 | cut -d ' ' -f 2

โดยที่
-printf "% T @% p \ n"เพื่อกำหนดเกณฑ์การเรียงลำดับ (วันที่),
'sort -nr'สำหรับการเรียงลำดับตามวันที่,
หัว -10สำหรับการแสดงรายการ 10 อันดับแรกผลการ
ตัด -d '' -f 2สำหรับการตัด การประทับเวลาชั้นนำในแต่ละบรรทัด


cut -d ' ' -f 2จะแตกถ้าชื่อไฟล์มีช่องว่าง
F. Hauri

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.