ลบไฟล์ที่เก่าที่สุด


9

ฉันกำลังพยายามลบไฟล์เก่าออกจากไดเรกทอรีและเหลือเพียง 3 ไฟล์ใหม่ล่าสุด

cd /home/user1/test

while [ `ls -lAR | grep ^- | wc -l` < 3 ] ; do

    rm `ls -t1 /home/user/test | tail -1`
    echo " - - - "

done

มีบางอย่างผิดปกติกับข้อความสั่งแบบมีเงื่อนไข

คำตอบ:


9

หากคุณต้องการวนซ้ำไฟล์อย่าใช้ls * tl; dr มีหลายสถานการณ์ที่คุณจะต้องทำการลบไฟล์ผิดหรือแม้แต่ไฟล์ทั้งหมด

ที่กล่าวว่าน่าเสียดายที่นี่เป็นสิ่งที่หากินใน Bash มีคำตอบที่ใช้งานได้สำหรับคำถามที่ซ้ำกัน ของฉันที่เก่ากว่าfind_date_sortedซึ่งคุณสามารถใช้กับการแก้ไขเล็กน้อย:

counter=0
while IFS= read -r -d '' -u 9
do
    let ++counter
    if [[ counter -gt 3 ]]
    then
        path="${REPLY#* }" # Remove the modification time
        echo -e "$path" # Test
        # rm -v -- "$path" # Uncomment when you're sure it works
    fi
done 9< <(find . -mindepth 1 -type f -printf '%TY-%Tm-%TdT%TH:%TM:%TS %p\0' | sort -rz) # Find and sort by date, newest first

* ไม่มีคนทำผิดฉันเคยใช้มาlsก่อน แต่มันไม่ปลอดภัยจริงๆ

แก้ไข: ใหม่find_date_sortedพร้อมการทดสอบหน่วย


ฉันสองส่วนเกี่ยวกับการแยกไม่ ls สคริปต์ก็ยังเรียบร้อย แต่ฉันคิดว่ามันสามารถทำได้ในหนึ่งซับให้ฉันตรวจสอบ ...
rahmu

ดีที่คุณสามารถเสมอขนาดกะทัดรัดรหัสทุบตีเป็นหนึ่งซับ แต่ปัญหาคือว่ามันจะอ่าน :)
l0b0

2
หากฉันอาจขโมยความคิดจาก @ Peter.O อย่างไร้ความปราณีลอง((++counter>3))เป็นแบบทดสอบของคุณ มันรวบรัดอย่างดี สำหรับผู้ oneliners: ถ้าความกะทัดรัดเป็นข้อกังวลห่อรหัสในฟังก์ชั่นแล้วไม่ต้องกังวลกับมัน
Sorpigal

ทางลัด @Sorpigal Neat
l0b0

5

ในการลบทั้งหมดยกเว้น 3 ไฟล์ใหม่ล่าสุดโดยใช้ zsh glob คุณสามารถใช้Om(ตัวพิมพ์ใหญ่ O) เพื่อเรียงลำดับไฟล์จากเก่าไปหาใหม่และเป็นตัวห้อยเพื่อดึงไฟล์ที่คุณต้องการ

rm ./*(Om[1,-4])
#    | ||||  ` stop at the 4th to the last file (leaving out the 3 newest)
#    | |||` start with first file (oldest in this case)
#    | ||` subscript to pick one or a range of files
#    | |` look at modified time
#    | ` sort in descending order
#    ` start by looking at all files

ตัวอย่างอื่น ๆ :

# delete oldest file (both do the same thing)
rm ./*(Om[1])
rm ./*(om[-1])

# delete oldest two files
rm ./*(Om[1,2])

# delete everything but the oldest file
rm ./*(om[1,-2])

5

โดยวิธีที่ง่ายที่สุดคือการใช้ zsh และคุณสมบัติรอบตัว : Omเพื่อจัดเรียงตามอายุที่ลดลง (เช่นเก่าที่สุดก่อน) และ[1,3]เพื่อรักษาเฉพาะการแข่งขันสามครั้งแรกเท่านั้น

rm ./*(Om[1,3])

ดูเพิ่มเติมฉันจะกรอง glob ใน zsh ได้อย่างไรสำหรับตัวอย่างเพิ่มเติม

และทำตามคำแนะนำของ l0b0 : รหัสของคุณจะพังอย่างน่ากลัวหากคุณมีชื่อไฟล์ที่มีอักขระพิเศษของเชลล์


Woa woa ถือรถไฟนี่เป็นโซลูชั่นที่สมบูรณ์แบบใน 1 บรรทัดหรือไม่?
MetaGuru

2
@ Ryan นั่นคือ zsh สำหรับคุณ
Gilles 'หยุดความชั่วร้าย'

1

คุณสามารถใช้ฟังก์ชั่นต่อไปนี้เพื่อรับไฟล์ใหม่ล่าสุดในไดเรกทอรี:

newest_in() 
{ 
    local newest=$1

    for f;do [[ $f -nt $newest ]] && newest="$f"; done;

    printf '%s\n' "$newest"
}

ให้ไฟล์ชุดต่าง ๆ โดยการเปิดไฟล์ใหม่ล่าสุดหลังจากการทำซ้ำแต่ละครั้ง

เคล็ดลับ:หากคุณถือชุดไฟล์เริ่มต้นในอาร์เรย์ที่เรียกว่า "$ {files [@]}" ให้บันทึกดัชนีของไฟล์ล่าสุดที่พบและunset 'files[index]'ก่อนการทำซ้ำครั้งถัดไป

การใช้งาน: newest_in [set of files/directories]

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

[rany$] newest_in ./*
foo.txt
[rany$]

-1

ขั้นแรก-Rตัวเลือกสำหรับการเรียกซ้ำซึ่งอาจไม่ใช่สิ่งที่คุณต้องการซึ่งจะค้นหาในไดเรกทอรีย่อยทั้งหมดเช่นกัน ประการที่สอง<ผู้ประกอบการ (เมื่อไม่ได้ถูกมองว่าเป็นการเปลี่ยนเส้นทาง) สำหรับการเปรียบเทียบสตริง -ltคุณอาจต้องการ ลอง:

while [ `ls -1A | grep ^- | wc -l` -lt 3 ]

แต่ฉันจะใช้หาที่นี่:

while [ `find . -maxdepth 1 -type f -print | wc -l` -lt 3 ]

ทั้งสองจะล้มเหลวหากชื่อไฟล์หนึ่งชื่อขึ้นไปมี '$ \ n'
Rany Albeg Wein

-1

ฉันรู้ว่ามันเป็นบาปที่จะแยกวิเคราะห์lsแต่สิ่งที่เกี่ยวกับเรื่องนี้:

find . -type f -maxdepth 1 | xargs ls -ltr | sed '1,3d' | awk '{print $9}' | xargs rm

การทดสอบอย่างรวดเร็วพร้อมไฟล์ว่าง 5 ไฟล์:

$ >1
$ >2
$ >3
$ >4
$ >5
$ find . -type f -maxdepth 1 | xargs ls -lt | sed '1,3d' | awk '{print $9}' | xargs rm
$ ls -1
3
4
5

อันนี้จะล้มเหลวด้วยเหตุผลสองประการ - แยกวิเคราะห์การlsส่งออกและการใช้findและxargsร่วมกันในทางที่ผิด ถ้าคุณรวมfindและxargsขอแนะนำให้คุณใช้finds -print0และตามxargss -Oตัวเลือก อ่านเกี่ยวกับการใช้การค้นหาสำหรับข้อมูลเพิ่มเติมเกี่ยวกับเรื่อง คุณอาจต้องการดูและอ่านเกี่ยวกับสาเหตุที่การแยกวิเคราะห์ lsแย่มาก
Rany Albeg Wein

-2

หนึ่งซับนี้ทำทุกอย่างที่ฉันคิด:

ls -t1 /home/user/test | tail -n +4 | xargs -I{} rm -- "{}"

ls เป็นเครื่องมือสำหรับการดูข้อมูลไฟล์แบบโต้ตอบ เอาต์พุตถูกจัดรูปแบบสำหรับมนุษย์และจะทำให้เกิดข้อบกพร่องในสคริปต์ ใช้ globs หรือค้นหาแทน เข้าใจว่าทำไม: mywiki.wooledge.org/ParsingLs
Rany Albeg Wein

-2

นี่คือทางออกหนึ่ง:

rm /appserver/webapplogs/$(ls -t1 /appserver/webapplogs/|tail -1)

1
@bakbak ls เป็นเครื่องมือสำหรับการดูข้อมูลไฟล์แบบโต้ตอบ เอาต์พุตถูกจัดรูปแบบสำหรับมนุษย์และจะทำให้เกิดข้อบกพร่องในสคริปต์ ดูที่นี่จะเข้าใจว่าทำไม พูดถึงคำตอบของคุณโดยเฉพาะ - อันนี้จะแตกถ้าไฟล์หนึ่งไฟล์ขึ้นไปมีอักขระ $ '\ n' นอกจากนี้การแทนที่คำสั่ง (เช่น $ (... )) ยังไม่มีเครื่องหมายคำพูดคู่ซึ่งทำให้เกิดเรื่องสำคัญอีกเรื่องหนึ่ง - การแยกคำ !
Rany Albeg Wein
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.