ฉันกำลังมองหาเปลือกหนึ่งซับเพื่อค้นหาไฟล์ที่เก่าแก่ที่สุดในต้นไม้ไดเรกทอรี
ฉันกำลังมองหาเปลือกหนึ่งซับเพื่อค้นหาไฟล์ที่เก่าแก่ที่สุดในต้นไม้ไดเรกทอรี
คำตอบ:
งานนี้ (อัปเดตเพื่อรวมคำแนะนำของ Daniel Andersson):
find -type f -printf '%T+ %p\n' | sort | head -n 1
find
ว่างเนื่องจากบรรทัดแรกของฉันจากที่นี่ว่างเปล่าเนื่องจากความจริงที่ว่าฉันมีชื่อไฟล์มีการขึ้นบรรทัดใหม่
อันนี้พกพาได้มากกว่านิดหน่อยและเพราะว่ามันไม่ได้ใช้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 ฉันไม่รู้ว่าทำไมฉันไม่ได้รับข้อผิดพลาดที่คล้ายกันเมื่อฉันส่งออกเรียงลำดับของหัวในการแก้ปัญหาของฉัน
head
คำสั่งที่หยุดทันทีที่ได้อ่านบรรทัดและ "หยุด" ไพพ์ฉันคิด คุณไม่ได้รับข้อผิดพลาดเพราะsort
ดูเหมือนจะไม่บ่นเกี่ยวกับมัน แต่ls
ทำในอีกกรณีหนึ่ง
xargs
ต้องการเรียกใช้ls
มากกว่าหนึ่งครั้ง ในกรณีดังกล่าวเอาต์พุตที่เรียงลำดับของการเรียกใช้หลายรายการจะจบลงด้วยการต่อกันเมื่อพวกเขาควรรวมเข้าด้วยกัน
ls
มันและลูกตาไฟล์ที่เก่าแก่ที่สุด, การแก้ปัญหาของคุณอาจจะเหยียบย่ำขีดจำกัดความยาวบรรทัดคำสั่งที่ก่อให้เกิดls
การถูกเรียกหลายครั้ง คุณจะได้คำตอบที่ผิด แต่คุณจะไม่มีทางรู้
คำสั่งคำสั่งต่อไปนี้รับประกันว่าจะทำงานกับชื่อไฟล์แปลก ๆ ทุกชนิด:
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
แม้ว่าคำตอบที่ได้รับการยอมรับและอื่น ๆ ที่นี่ทำงานถ้าคุณมีต้นไม้ที่มีขนาดใหญ่มากพวกเขาทั้งหมดจะเรียงลำดับกลุ่มของไฟล์ทั้งหมด
จะดีกว่าถ้าเราสามารถบันทึกรายการเหล่านั้นและติดตามรายการที่เก่าที่สุดโดยไม่จำเป็นต้องเรียงลำดับเลย
นั่นเป็นเหตุผลที่ฉันคิดวิธีแก้ปัญหาทางเลือกนี้:
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}'
คำสั่งอธิบายแล้ว:
ใช้มัน
~ $ 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}'
ls
ไม่ดีสำหรับการเขียนสคริปต์เนื่องจากเอาต์พุตไม่ได้มีไว้สำหรับเครื่อง ตามที่คุณระบุไว้แล้วว่าfind
ดีสำหรับการเขียนสคริปต์ แต่อาจเป็นการดีที่จะเพิ่มข้อมูลนั้นก่อนที่จะบอกls
วิธีแก้ไข
กรุณาใช้ ls - หน้าคนบอกวิธีการสั่งซื้อไดเรกทอรี
ls -clt | head -n 2
-n 2 คือดังนั้นคุณไม่ได้รับ "ผลรวม" ในผลลัพธ์ หากคุณต้องการชื่อไฟล์เท่านั้น
ls -t | head -n 1
และถ้าคุณต้องการรายการตามลำดับปกติ (รับไฟล์ใหม่ล่าสุด)
ls -tr | head -n 1
ง่ายกว่าการใช้การค้นหาเร็วกว่าและแข็งแกร่งกว่า - ไม่ต้องกังวลกับรูปแบบการตั้งชื่อไฟล์ ควรทำงานกับระบบเกือบทั้งหมดด้วย
find ! -type d -printf "%T@ %p\n" | sort -n | head -n1
sort -n
ต้องการเปิดใช้งานการเรียงลำดับตัวเลขใช้
ดูเหมือนว่าโดย "เก่าที่สุด" คนส่วนใหญ่สันนิษฐานว่าคุณหมายถึง "เวลาแก้ไขที่เก่าที่สุด" นั่นอาจแก้ไขได้ตามการตีความที่เข้มงวดที่สุดของ "เก่าที่สุด" แต่ในกรณีที่คุณต้องการเวลาที่เก่าที่สุดเข้าถึงได้ฉันจะแก้ไขคำตอบที่ดีที่สุดดังนี้:
find -type f -printf '%A+ %p\n' | sort | head -n 1
%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'
พิมพ์วันที่และชื่อไฟล์ในสองคอลัมน์sort | head -n1
เก็บบรรทัดที่สอดคล้องกับไฟล์ที่เก่าที่สุดecho $2
แสดงคอลัมน์ที่สองเช่นชื่อไฟล์
find -type f -printf '%T+ %p\n' | sort | head -1