ฉันจะลบทั้งหมดยกเว้น 10 ไฟล์ใหม่ล่าสุดใน Linux ได้อย่างไร


49

ฉันพยายามทำให้ไดเรกทอรีเต็มไปด้วยแฟ้มบันทึกที่จัดการได้ ทุกคืนฉันต้องการลบทั้งหมดยกเว้น 10 รายการล่าสุด ฉันจะทำสิ่งนี้ได้ในคำสั่งเดียว?


3
ลองดูที่ logrotate
knittl


@michael ฉันจะทำซ้ำสิ่งนั้นได้อย่างไรถ้าการสนทนาของฉันถูกสร้างขึ้นก่อน
dev4life

@ Novaherenow "ของคุณ"? ฉันไม่เห็นชื่อของคุณในคำถามใดคำถามหนึ่งดังนั้นฉันไม่แน่ใจว่าคุณหมายถึงอะไร ความคิดเห็นของฉันไม่ได้ระบุว่าสิ่งใดเป็นความซ้ำซ้อน แต่มันไม่สำคัญ - มันเป็นแค่ความคิดเห็นพร้อมลิงค์ สามารถเพิ่มให้กับคำถามใดคำถามหนึ่งหรือทั้งสองคำถาม มันขึ้นอยู่กับคนอื่น - ผู้ดูแลระบบ - เพื่อทำเครื่องหมายอย่างใดอย่างหนึ่งเป็นอีกรายการที่ซ้ำกัน ไม่มีเจตนาอันชั่วร้ายที่ตั้งใจและไม่ควรมีใครรับรู้ สำคัญกว่าคำถามใดคำถามแรกคือคำถามใดมีคำตอบที่ดีที่สุด - อีกครั้งลิงก์ช่วยการสนทนานี้โดยไม่ระบุคำตอบ
ไมเคิล

@ ไมเคิลว้าว นั่นแปลกจริงๆ หัวข้อนี้เปิดโดยฉัน แต่เห็นได้ชัดว่าไม่ใช่ชื่อผู้ใช้ของฉัน แต่ฉันได้รับแจ้งเกี่ยวกับหัวข้อนี้
dev4life

คำตอบ:


58

สำหรับโซลูชันแบบพกพาและเชื่อถือได้ลองสิ่งนี้:

ls -1tr | head -n -10 | xargs -d '\n' rm -f --

tail -n -10ไวยากรณ์ในหนึ่งในคำตอบอื่น ๆ ดูเหมือนจะไม่ทำงานทุกที่ (คือไม่ได้อยู่ในระบบ RHEL5 ของฉัน)

และการใช้$()หรือ``บนบรรทัดคำสั่งของการrmเรียกใช้ความเสี่ยงของ

  1. แยกชื่อไฟล์ด้วยช่องว่างและ
  2. เกินขีด จำกัด อักขระบรรทัดคำสั่งสูงสุด

xargsแก้ไขปัญหาทั้งสองนี้เพราะมันจะหาได้โดยอัตโนมัติว่ามีจำนวนเท่าใดที่สามารถส่งผ่านได้ภายในขีด จำกัด อักขระและโดย-d '\n'จะแยกเฉพาะที่ขอบเขตบรรทัดของอินพุต ในทางเทคนิคการทำเช่นนี้อาจทำให้เกิดปัญหากับชื่อไฟล์ที่ขึ้นบรรทัดใหม่ แต่นั่นก็น้อยกว่าชื่อไฟล์ที่มีช่องว่างและวิธีเดียวที่จะทำให้บรรทัดใหม่มีความซับซ้อนมากขึ้น

หากคุณไม่มี xargs (ระบบ AIX เก่าอาจเป็นไปได้) คุณสามารถทำให้เป็นวนซ้ำได้:

ls -1tr | head -n -10 | while IFS= read -r f; do
  rm -f "$f"
done

สิ่งนี้จะช้าลงเล็กน้อยเนื่องจากแยกออกจากกันrmสำหรับแต่ละไฟล์ แต่จะยังคงหลีกเลี่ยงการเตือน 1 และ 2 ข้างต้น (แต่ยังคงทุกข์ทรมานจากการขึ้นบรรทัดใหม่ในชื่อไฟล์)


@HaukeLaging: จากhead(1)หน้าคน:-n, --lines=[-]K print the first K lines instead of the first 10; with the leading '-', print all but the last K lines of each file
ไอแซคฟรีแมน

บน Solaris 10 headและxargsให้ข้อผิดพลาด ตัวเลือกที่ถูกต้องและhead -n 10 xargs rm -fคำสั่งแบบเต็มคือls -1tr ./ | head -n 10 | xargs rm -rf
DmitrySandalov

1
หมายเหตุls -1trคือหมายเลขหนึ่งไม่ใช่ตัวอักษร "L"
ผู้ใช้ shonky linux

1
ควรสังเกตว่าการขึ้นบรรทัดใหม่นั้นหายาก แต่มีอักขระที่ถูกต้องในชื่อไฟล์ต่อ ซึ่งหมายความว่าหากคุณมีไฟล์ "ที่" และ "ที่ \ n ทุกอย่าง" หากสคริปต์นี้พบ "ที่ \ n ทุกอย่าง" มันจะลบ "ว่า" ข้อผิดพลาดเมื่อไม่สามารถลบ "สิ่ง" และออกจาก "that \ nthing" (เป้าหมายที่ตั้งใจไว้) ไม่ได้รับผลกระทบ
Synthead

1
@IsaacFreeman ฉันได้ลบคำแนะนำที่ไม่ดีของฉันไชโย
Walf

20

รหัสที่คุณต้องการรวมไว้ในสคริปต์ของคุณคือ

 rm -f $(ls -1t /path/to/your/logs/ | tail -n +11)

-1(หนึ่งตัวเลข) ตัวเลือกพิมพ์ไฟล์บนบรรทัดเดียวแต่ละเพื่อความปลอดภัย -fตัวเลือกที่จะrmบอกว่ามันจะไม่สนใจไฟล์ที่ไม่มีอยู่จริงเมื่อlsผลตอบแทนอะไร


โปสเตอร์ต้นฉบับที่นี่ ฉันลองคำสั่งนี้ แต่มันใช้งานไม่ได้ - ฉันได้รับข้อผิดพลาด "rm: missing operand"
user75814

2
คุณใช้เส้นทางที่ถูกต้องหรือไม่? เห็นได้ชัดว่า/path/to/your/logsมีไว้สำหรับคุณที่จะเข้าสู่เส้นทางที่ถูกต้อง ในการค้นหาข้อบกพร่องดำเนินการชิ้นส่วนls -t /path/...และls -t /path/... | tail -n +11เพียงอย่างเดียวและตรวจสอบว่าผลลัพธ์ที่ถูกต้อง
Daniel Böhmer

1
@HaukeLaging ฉันค่อนข้างแน่ใจว่าคุณมีบางอย่างผิดปกติ ใจ+ก่อนหมายเลข มันtailไม่ได้พิมพ์องค์ประกอบสุดท้าย n แต่องค์ประกอบทั้งหมดเริ่มต้นจาก n'th ฉันเช็คอินอีกครั้งและคำสั่งควรลบเฉพาะองค์ประกอบที่เก่ากว่า 10 ไฟล์ล่าสุดในทุกกรณี
Daniel Böhmer

@ รัศมีแน่นอนขอโทษ
Hauke ​​Laging

2
ฉันคิดว่าคำตอบของคุณนั้นอันตรายมากlsพิมพ์ชื่อไฟล์ไม่ใช่เส้นทางดังนั้นคุณrm -fจะพยายามลบไฟล์ในไดเรกทอรีปัจจุบัน
Jürgen Steinblock

14

เห็นได้ชัดว่าการแยกวิเคราะห์เป็นความชั่วร้ายls

หากแต่ละไฟล์ถูกสร้างขึ้นทุกวันและคุณต้องการเก็บไฟล์ไว้ภายใน 10 วันที่ผ่านมาคุณสามารถทำได้:

find /path/to/files -mtime 10 -delete

หรือถ้าแต่ละไฟล์ถูกสร้างโดยพลการ:

find /path/to/files -maxdepth 1 -type f -printf '%Ts\t%P\n' | sort -n | head -n -10 | cut -f 2- | xargs rm -rf

5
-mtime 10 -deleteลบเฉพาะไฟล์ที่ถูกแก้ไขเมื่อ 10 วันก่อน ไฟล์ที่เก่ากว่าจะไม่ถูกลบ -mtime +11 -deleteจะลบไฟล์ที่ถูกแก้ไขตั้งแต่ 11 วันขึ้นไปและออกจากไฟล์บันทึก 10 วันล่าสุด
Markus

1
ฉันคิดว่าจำเป็นต้องใช้%pแทนเพื่อที่ว่าไฟล์จะได้รับเส้นทางที่สมบูรณ์ มิฉะนั้นการใช้งานไม่ได้ %Pprintfrm -rf
jalopaba

9

เครื่องมือเช่น logrotate ทำเพื่อคุณ มันทำให้การจัดการบันทึกง่ายขึ้นมาก คุณยังสามารถรวมรูทีนการล้างข้อมูลเพิ่มเติมตามที่รัศมีแนะนำได้



1

จากที่นี่ :

#! /bin/sh
# keepnewest
#
# Simple directory trimming tool to handle housekeeping
# Scans a directory and deletes all but the N newest files
#
# Usage: cleanup <dir> <number of files to keep>
#
# v 1.0 Piers Goodhew 1/mar/2007. No rights retained.


if [ $# -ne 2 ]; then
  echo 1>&2 "Usage: $0 <dir> <number of files to keep>"
  exit 1
fi

cd $1
files_in_dir=`ls | wc -l`
files_to_delete=`expr $files_in_dir - $2`
if [ $files_to_delete -gt 0 ]; then
  ls -t | tail -n $files_to_delete | xargs rm
  if [ $? -ne 0 ]; then
    echo "An error ocurred deleting the files"
    exit 1
  else
    echo "$files_to_delete file(s) deleted."
  fi
else
  echo "nothing to delete!"
fi

1
ขอบคุณที่ให้คำตอบนี้ ในขณะที่การให้รหัสเช่นนี้มีประโยชน์ แต่ก็ยังช่วยให้ข้อมูลเพิ่มเติมบางอย่างเกี่ยวกับวิธีการใช้หรือสิ่งที่รหัสทำ คุณสามารถใช้ปุ่มแก้ไขเพื่อทำการปรับปรุงโพสต์ของคุณในอนาคต
nhinkle

1

ใน Bash คุณสามารถลอง:

ls -1t | (i=0; while read f; do
  if [ $i -lt 10 ]; then
    ((i++))
    continue
  else
    rm -f "$f"
  fi
done)

นี่เป็นการข้าม als ใหม่ล่าสุด 10 รายการลบส่วนที่เหลือ logrotate อาจจะดีกว่าฉันแค่ต้องการแก้ไขคำตอบที่เกี่ยวข้องกับเชลล์ผิด


1

ไม่แน่ใจว่าจะช่วยใครได้ แต่เพื่อหลีกเลี่ยงปัญหาที่อาจเกิดขึ้นกับตัวอักษร wonky ฉันเพิ่งlsทำการเรียงลำดับ แต่ใช้ไฟล์inodeสำหรับการลบ

สำหรับไดเรกทอรีปัจจุบันจะเก็บ 10 ไฟล์ล่าสุดตามเวลาการแก้ไข

ls -1tri | awk '{print $1}' | head -n -10 | xargs -n1 -t -Iinode find . -inum inode -exec rm -i {} \;


0

ฉันต้องการโซลูชันที่สง่างามสำหรับ busybox (เราเตอร์) โซลูชั่น xargs หรือ array ทั้งหมดไม่มีประโยชน์กับฉัน - ไม่มีคำสั่งดังกล่าวให้ใช้งาน find และ mtime ไม่ใช่คำตอบที่ถูกต้องเนื่องจากเรากำลังพูดถึง 10 รายการและไม่จำเป็นต้อง 10 วัน คำตอบของ Espo นั้นสั้นที่สุดและสะอาดที่สุด

ข้อผิดพลาดเกี่ยวกับช่องว่างและเมื่อไม่มีไฟล์ที่จะลบทั้งคู่ก็สามารถแก้ไขได้ด้วยวิธีมาตรฐาน:

rm "$(ls -td *.tar | awk 'NR>7')" 2>&-

Bit รุ่นทางการศึกษามากขึ้น: เราสามารถทำได้ทุกอย่างถ้าเราใช้ awk ต่างกัน โดยปกติฉันใช้วิธีนี้ในการส่งผ่าน (กลับ) ตัวแปรจาก awk ไปยัง sh เมื่อเราอ่านตลอดเวลาที่ไม่สามารถทำได้ฉันขอแตกต่าง: นี่คือวิธีการ

ตัวอย่างของไฟล์. tar ที่ไม่มีปัญหาเกี่ยวกับช่องว่างในชื่อไฟล์ ในการทดสอบให้แทนที่ "rm" ด้วย "ls"

eval $(ls -td *.tar | awk 'NR>7 { print "rm \"" $0 "\""}')

คำอธิบาย:

ls -td *.tarแสดงรายการไฟล์. tar ทั้งหมดที่เรียงลำดับตามเวลา หากต้องการใช้กับไฟล์ทั้งหมดในโฟลเดอร์ปัจจุบันให้ลบส่วน "d * .tar"

awk 'NR>7... ข้าม 7 บรรทัดแรก

print "rm \"" $0 "\"" สร้างบรรทัด: rm "ชื่อไฟล์"

eval รันมัน

เนื่องจากเราใช้rmฉันจะไม่ใช้คำสั่งด้านบนในสคริปต์! การใช้งานที่ชาญฉลาดคือ:

(cd /FolderToDeleteWithin && eval $(ls -td *.tar | awk 'NR>7 { print "rm \"" $0 "\""}'))

ในกรณีของการใช้ls -tคำสั่งจะไม่ทำอันตรายใด ๆ ในตัวอย่างที่โง่เช่น: และtouch 'foo " bar' touch 'hello * world'ไม่ใช่ว่าเราเคยสร้างไฟล์ด้วยชื่อดังกล่าวในชีวิตจริง!

sidenote หากเราต้องการส่งตัวแปรไปยัง sh ด้วยวิธีนี้เราเพียงแค่ปรับเปลี่ยนการพิมพ์:

print "VarName="$1

การตั้งค่าตัวแปรค่าของVarName $1สามารถสร้างตัวแปรหลายตัวในครั้งเดียว สิ่งนี้VarNameกลายเป็นตัวแปร sh ปกติและสามารถใช้งานได้ตามปกติในสคริปต์หรือเชลล์หลังจากนั้น ดังนั้นในการสร้างตัวแปรด้วย awk และให้กลับไปที่เชลล์:

eval $(ls -td *.tar | awk 'NR>7 { print "VarName="$1 }'); echo "$VarName"

0

ฉันยอมรับว่า ls การแยกวิเคราะห์เป็นสิ่งที่ชั่วร้าย!

ตรวจสอบให้แน่ใจว่าไฟล์ 5 ไฟล์สุดท้ายเท่านั้นที่ถูกเก็บใน/srv/backupsพา ธ

find /srv/backups -maxdepth 1 -type f -printf '%Ts\t%P\n' \
    | sort -rn \
    | tail -n +6 \
    | cut -f2- \
    | xargs -r r

0

ตามการตอบสนองของไอแซกฟรีแมน แต่ทำงานกับไดเรกทอรีใด ๆ

ls -1tr $PATH_TO_DELETE/* | head -n -10 | xargs -d '\n' rm -f --

คุณสามารถตั้งค่าคำนำหน้าเช่น $PATH_TO_DELETE/testFi*

หากคุณใช้*หลังจากPATH lsชื่อไฟล์สัมบูรณ์จะส่งออกอย่างน้อยใน "my" bash :)

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