ฉันจะหาไฟล์ที่เก่าที่สุดในแผนผังไดเรกทอรีได้อย่างไร


72

ฉันกำลังมองหาเปลือกหนึ่งซับเพื่อค้นหาไฟล์ที่เก่าแก่ที่สุดในต้นไม้ไดเรกทอรี

คำตอบ:


72

งานนี้ (อัปเดตเพื่อรวมคำแนะนำของ Daniel Andersson):

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

8
พิมพ์น้อยลง:find -type f -printf '%T+ %p\n' | sort | head -1
Daniel Andersson

1
ฉันได้รับพื้นที่findว่างเนื่องจากบรรทัดแรกของฉันจากที่นี่ว่างเปล่าเนื่องจากความจริงที่ว่าฉันมีชื่อไฟล์มีการขึ้นบรรทัดใหม่
林果皞

1
ฉันสามารถถามได้ไหมว่าสิ่งนี้ใช้วันที่สร้างหรือแก้ไข?
MrMesees

1
Linux ไม่ได้จัดเก็บวันที่สร้างไฟล์ไว้ที่ใด [*] สิ่งนี้ใช้วันที่แก้ไข [*] สิ่งนี้ไม่จริง ext4 เก็บวันที่สร้าง inode แต่จะไม่เปิดเผยผ่านการเรียกของระบบใด ๆ และคุณจำเป็นต้องใช้ debugfs เพื่อดู)
Marius Gedminas

11

อันนี้พกพาได้มากกว่านิดหน่อยและเพราะว่ามันไม่ได้ใช้findส่วนขยายGNU -printfดังนั้นจึงสามารถใช้งานกับ BSD / OS X ได้เช่นกัน:

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

ข้อเสียเพียงอย่างเดียวที่นี่ก็คือมันค่อนข้าง จำกัด ขนาดARG_MAX(ซึ่งควรจะไม่เกี่ยวข้องกับเมล็ดใหม่กว่า) ดังนั้นถ้ามีมากกว่าgetconf ARG_MAXตัวละครกลับ (262,144 ในระบบของฉัน) ก็ไม่ได้ให้ผลที่ถูกต้อง มันยังไม่เข้ากันได้กับ POSIX เพราะ-print0และxargs -0ไม่ใช่

แนวทางแก้ไขเพิ่มเติมสำหรับปัญหานี้มีการระบุไว้ที่นี่: ฉันจะค้นหาไฟล์ (ล่าสุด, เก่าที่สุด, เก่าที่สุด) ในไดเรกทอรีได้อย่างไร - วิกิพีเดียของเกร็ก


วิธีนี้ใช้งานได้เช่นกัน แต่มันก็ปล่อยxargs: ls: terminated by signal 13ข้อผิดพลาดเป็นผลข้างเคียง ฉันคาดเดาว่า SIGPIPE ฉันไม่รู้ว่าทำไมฉันไม่ได้รับข้อผิดพลาดที่คล้ายกันเมื่อฉันส่งออกเรียงลำดับของหัวในการแก้ปัญหาของฉัน
Marius Gedminas

เวอร์ชันของคุณยังง่ายกว่าในการพิมพ์จากหน่วยความจำ :-)
Marius Gedminas

ใช่มันเป็นท่อที่ขาด ฉันไม่ได้รับสิ่งนี้ทั้ง GNU และ BSD ของคำสั่งเหล่านั้นทั้งหมด แต่มันเป็นheadคำสั่งที่หยุดทันทีที่ได้อ่านบรรทัดและ "หยุด" ไพพ์ฉันคิด คุณไม่ได้รับข้อผิดพลาดเพราะsortดูเหมือนจะไม่บ่นเกี่ยวกับมัน แต่lsทำในอีกกรณีหนึ่ง
slhck

4
สิ่งนี้จะหยุดหากมีชื่อไฟล์จำนวนมากที่xargsต้องการเรียกใช้lsมากกว่าหนึ่งครั้ง ในกรณีดังกล่าวเอาต์พุตที่เรียงลำดับของการเรียกใช้หลายรายการจะจบลงด้วยการต่อกันเมื่อพวกเขาควรรวมเข้าด้วยกัน
Nicole Hamilton

2
ฉันคิดว่ามันแย่กว่าการโพสต์สคริปต์ที่สมมติว่าชื่อไฟล์ไม่มีช่องว่าง หลายครั้งที่จะใช้งานได้เพราะชื่อไฟล์ไม่มีช่องว่าง และเมื่อพวกเขาล้มเหลวคุณจะได้รับข้อผิดพลาด แต่สิ่งนี้ไม่น่าที่จะทำงานในกรณีจริงและความล้มเหลวจะไม่ถูกค้นพบ บนต้นไม้ไดเรกทอรีใด ๆ ขนาดใหญ่พอที่จะทำให้คุณไม่สามารถเพียงแค่lsมันและลูกตาไฟล์ที่เก่าแก่ที่สุด, การแก้ปัญหาของคุณอาจจะเหยียบย่ำขีดจำกัดความยาวบรรทัดคำสั่งที่ก่อให้เกิดlsการถูกเรียกหลายครั้ง คุณจะได้คำตอบที่ผิด แต่คุณจะไม่มีทางรู้
นิโคลแฮมิลตัน

11

คำสั่งคำสั่งต่อไปนี้รับประกันว่าจะทำงานกับชื่อไฟล์แปลก ๆ ทุกชนิด:

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

การใช้ null ไบต์ ( \0) แทนอักขระ linefeed ( \n) ตรวจสอบให้แน่ใจว่าผลลัพธ์ของการค้นหาจะยังคงเข้าใจได้ในกรณีที่ชื่อไฟล์หนึ่งในนั้นมีอักขระ linefeed

-zสวิทช์ทำให้ทั้งจัดเรียงและ grep ตีความไบต์เท่านั้น null เป็นตัวละครในตอนท้ายของบรรทัด เนื่องจากไม่มีสวิตช์สำหรับหัวดังกล่าวเราจึงใช้grep -m 1แทน (เกิดขึ้นเพียงครั้งเดียว)

คำสั่งจะถูกจัดเรียงตามเวลาดำเนินการ

  • คำสั่งแรกจะช้าที่สุดเนื่องจากต้องแปลง mtime ของไฟล์ทุกไฟล์เป็นรูปแบบที่มนุษย์สามารถอ่านได้ก่อนแล้วจึงเรียงลำดับสตริงเหล่านั้น ท่อเพื่อแมวหลีกเลี่ยงการระบายสีเอาท์พุท

  • คำสั่งที่สองเร็วกว่าเล็กน้อย ในขณะที่มันยังคงทำการแปลงวันที่การเรียงลำดับตัวเลข ( sort -n) วินาทีที่ผ่านไปเนื่องจากยุค Unix นั้นเร็วกว่าเล็กน้อย sed ลบวินาทีตั้งแต่ Unix ยุค

  • คำสั่งสุดท้ายไม่มีการแปลงเลยและควรเร็วกว่าคำสั่งสองรายการแรกอย่างมาก คำสั่ง find จะไม่แสดง mtime ของไฟล์ที่เก่าที่สุดดังนั้นจึงจำเป็นต้องใช้ stat

หน้าคนที่เกี่ยวข้อง: find - grep - sed - sort - stat


5

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

จะดีกว่าถ้าเราสามารถบันทึกรายการเหล่านั้นและติดตามรายการที่เก่าที่สุดโดยไม่จำเป็นต้องเรียงลำดับเลย

นั่นเป็นเหตุผลที่ฉันคิดวิธีแก้ปัญหาทางเลือกนี้:

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

ฉันหวังว่ามันอาจจะเป็นความช่วยเหลือใด ๆ แม้ว่าคำถามจะค่อนข้างเก่า


แก้ไข 1:การเปลี่ยนแปลงนี้อนุญาตให้แยกไฟล์และไดเรกทอรีที่มีช่องว่าง มันเร็วพอที่จะออกมันในรูท/และค้นหาไฟล์ที่เก่าที่สุด

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

คำสั่งอธิบายแล้ว:

  • ls -lRU - time-style = long-iso "$ PWD" / * แสดงรายการไฟล์ทั้งหมด (*), รูปแบบยาว (l), เรียกซ้ำ (R) โดยไม่ต้องเรียงลำดับ (U) ให้รวดเร็วและไปที่ awk
  • จากนั้นให้เริ่ม BEGIN ด้วยการนับศูนย์ (เลือกได้สำหรับคำถามนี้) และตั้งค่าวันที่ที่เก่าที่สุดให้เป็นวันนี้ให้จัดรูปแบบ YearMonthDay
  • วงหลักก่อน
    • คว้าฟิลด์ที่ 6, วันที่, จัดรูปแบบปี - เดือน - วันและเปลี่ยนเป็น YearMonthDay (หาก ls ของคุณไม่ส่งออกด้วยวิธีนี้คุณอาจต้องปรับแต่ง)
    • การใช้การเรียกซ้ำจะมีบรรทัดส่วนหัวสำหรับไดเรกทอรีทั้งหมดในรูปแบบของ / directory / ที่นี่: คว้าสายนี้เป็นตัวแปร pat (แทน ":" สุดท้ายเป็น "/") และตั้งค่า $ 6 เป็นอะไรเพื่อหลีกเลี่ยงการใช้บรรทัดส่วนหัวเป็นบรรทัดไฟล์ที่ถูกต้อง
    • หากฟิลด์ $ 6 มีหมายเลขที่ถูกต้องก็จะเป็นวันที่ เปรียบเทียบกับ old old date
    • มันเก่ากว่าไหม จากนั้นบันทึกค่าใหม่สำหรับ old date oldd และ old filename oldf BTW, oldf ไม่เพียง แต่เป็นสนามที่ 8 แต่จากที่ 8 ถึงจุดสิ้นสุด นั่นเป็นเหตุผลที่มีการวนซ้ำซ้อนกันตั้งแต่ 8 ถึง NF (สิ้นสุด)
    • นับความก้าวหน้าโดยหนึ่ง
    • END โดยการพิมพ์ผลลัพธ์

ใช้มัน

~ $ time ls -lRU "$ PWD" / * | awk ฯลฯ

วันที่เก่าที่สุด: 19691231

ไฟล์: /home/.../.../backupold/.../EXAMPLES/how-to-program.txt

ทั้งหมดเปรียบเทียบ: 111438

จริง 0m1.135s

ผู้ใช้ 0m0.872s

sys 0m0.760s


แก้ไข 2:แนวคิดเดียวกัน, การแก้ปัญหาดีกว่าการใช้findดูที่เวลาในการเข้าถึง (ใช้%Tกับครั้งแรกprintfสำหรับการปรับเปลี่ยนเวลาหรือ%Cสำหรับการเปลี่ยนแปลงสถานะแทน)

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

แก้ไข 3:คำสั่งร้องใช้เวลาการแก้ไขและยังพิมพ์ความคืบหน้าแบบเพิ่มเนื่องจากพบไฟล์เก่าและเก่าซึ่งมีประโยชน์เมื่อคุณมีการประทับเวลาที่ไม่ถูกต้อง (เช่น 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}'

มันยังคงต้องการการ tweeking เพื่อยอมรับไฟล์ที่มีช่องว่าง ฉันจะทำเร็ว ๆ นี้
ดร. เบคโก

ฉันคิดว่าการแจง ls สำหรับไฟล์ที่มีช่องว่างไม่ใช่ความคิดที่ดี อาจจะใช้การค้นหา
ดร. เบคโก

เพียงแค่เรียกใช้ในต้นไม้ทั้งหมด "/" เวลาที่ใช้: ผลรวมทั้งหมด: 585744 จริง 2m14.017s ผู้ใช้ 0m8.181s sys 0m8.473s
Dr Beco

การใช้งานlsไม่ดีสำหรับการเขียนสคริปต์เนื่องจากเอาต์พุตไม่ได้มีไว้สำหรับเครื่อง ตามที่คุณระบุไว้แล้วว่าfindดีสำหรับการเขียนสคริปต์ แต่อาจเป็นการดีที่จะเพิ่มข้อมูลนั้นก่อนที่จะบอกlsวิธีแก้ไข
Sampo Sarrala

4

กรุณาใช้ ls - หน้าคนบอกวิธีการสั่งซื้อไดเรกทอรี

ls -clt | head -n 2

-n 2 คือดังนั้นคุณไม่ได้รับ "ผลรวม" ในผลลัพธ์ หากคุณต้องการชื่อไฟล์เท่านั้น

ls -t | head -n 1

และถ้าคุณต้องการรายการตามลำดับปกติ (รับไฟล์ใหม่ล่าสุด)

ls -tr | head -n 1

ง่ายกว่าการใช้การค้นหาเร็วกว่าและแข็งแกร่งกว่า - ไม่ต้องกังวลกับรูปแบบการตั้งชื่อไฟล์ ควรทำงานกับระบบเกือบทั้งหมดด้วย


6
ใช้ได้เฉพาะในกรณีที่ไฟล์อยู่ในไดเรกทอรีเดียวในขณะที่คำถามของฉันเกี่ยวกับโครงสร้างไดเรกทอรี
Marius Gedminas

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

สิ่งนี้จะทำงานไม่ถูกต้องหากมีไฟล์ที่เก่ากว่า 9 กันยายน 2544 (1000000000 วินาทีตั้งแต่ Unix epoch) sort -nต้องการเปิดใช้งานการเรียงลำดับตัวเลขใช้
เดนนิส

นี้จะช่วยให้หาฉันแฟ้ม แต่มันเป็นเรื่องยากที่จะเห็นวิธีการเก่าที่มันเป็นโดยไม่ต้องใช้คำสั่งที่สอง :)
Marius Gedminas

0

ดูเหมือนว่าโดย "เก่าที่สุด" คนส่วนใหญ่สันนิษฐานว่าคุณหมายถึง "เวลาแก้ไขที่เก่าที่สุด" นั่นอาจแก้ไขได้ตามการตีความที่เข้มงวดที่สุดของ "เก่าที่สุด" แต่ในกรณีที่คุณต้องการเวลาที่เก่าที่สุดเข้าถึงได้ฉันจะแก้ไขคำตอบที่ดีที่สุดดังนี้:

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

%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' พิมพ์วันที่และชื่อไฟล์ในสองคอลัมน์
  • sort | head -n1 เก็บบรรทัดที่สอดคล้องกับไฟล์ที่เก่าที่สุด
  • echo $2 แสดงคอลัมน์ที่สองเช่นชื่อไฟล์

1
ยินดีต้อนรับสู่ Super User! แม้ว่าสิ่งนี้อาจตอบคำถามได้ แต่มันจะเป็นคำตอบที่ดีกว่าถ้าคุณสามารถให้คำอธิบายได้ว่าทำไมถึงเป็นเช่นนั้น
DavidPostill

1
หมายเหตุมีหลายคนที่ขอคำอธิบายของคำตอบที่ถูกลบ (เหมือนกัน) ก่อนหน้า
DavidPostill

ตอบยากอะไร ค้นหา ./search/dirname - พิมพ์ f -printf '% T +% h /% f \ n' | จัดเรียง | head -n 1 มันแสดงให้เห็นสองคอลัมน์เป็นเวลาและเส้นทางของไฟล์ มีความจำเป็นต้องลบคอลัมน์แรก ใช้ set และ echo $ 2
Dima

1
คุณควรให้คำอธิบายแทนที่จะวางเพียงบรรทัดคำสั่งตามที่ผู้ใช้รายอื่นร้องขอ
Ob1lan

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