ฉันพยายามทำให้ไดเรกทอรีเต็มไปด้วยแฟ้มบันทึกที่จัดการได้ ทุกคืนฉันต้องการลบทั้งหมดยกเว้น 10 รายการล่าสุด ฉันจะทำสิ่งนี้ได้ในคำสั่งเดียว?
ฉันพยายามทำให้ไดเรกทอรีเต็มไปด้วยแฟ้มบันทึกที่จัดการได้ ทุกคืนฉันต้องการลบทั้งหมดยกเว้น 10 รายการล่าสุด ฉันจะทำสิ่งนี้ได้ในคำสั่งเดียว?
คำตอบ:
สำหรับโซลูชันแบบพกพาและเชื่อถือได้ลองสิ่งนี้:
ls -1tr | head -n -10 | xargs -d '\n' rm -f --
tail -n -10ไวยากรณ์ในหนึ่งในคำตอบอื่น ๆ ดูเหมือนจะไม่ทำงานทุกที่ (คือไม่ได้อยู่ในระบบ RHEL5 ของฉัน)
และการใช้$()หรือ``บนบรรทัดคำสั่งของการrmเรียกใช้ความเสี่ยงของ
xargsแก้ไขปัญหาทั้งสองนี้เพราะมันจะหาได้โดยอัตโนมัติว่ามีจำนวนเท่าใดที่สามารถส่งผ่านได้ภายในขีด จำกัด อักขระและโดย-d '\n'จะแยกเฉพาะที่ขอบเขตบรรทัดของอินพุต ในทางเทคนิคการทำเช่นนี้อาจทำให้เกิดปัญหากับชื่อไฟล์ที่ขึ้นบรรทัดใหม่ แต่นั่นก็น้อยกว่าชื่อไฟล์ที่มีช่องว่างและวิธีเดียวที่จะทำให้บรรทัดใหม่มีความซับซ้อนมากขึ้น
หากคุณไม่มี xargs (ระบบ AIX เก่าอาจเป็นไปได้) คุณสามารถทำให้เป็นวนซ้ำได้:
ls -1tr | head -n -10 | while IFS= read -r f; do
rm -f "$f"
done
สิ่งนี้จะช้าลงเล็กน้อยเนื่องจากแยกออกจากกันrmสำหรับแต่ละไฟล์ แต่จะยังคงหลีกเลี่ยงการเตือน 1 และ 2 ข้างต้น (แต่ยังคงทุกข์ทรมานจากการขึ้นบรรทัดใหม่ในชื่อไฟล์)
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
headและxargsให้ข้อผิดพลาด ตัวเลือกที่ถูกต้องและhead -n 10 xargs rm -fคำสั่งแบบเต็มคือls -1tr ./ | head -n 10 | xargs rm -rf
ls -1trคือหมายเลขหนึ่งไม่ใช่ตัวอักษร "L"
รหัสที่คุณต้องการรวมไว้ในสคริปต์ของคุณคือ
rm -f $(ls -1t /path/to/your/logs/ | tail -n +11)
-1(หนึ่งตัวเลข) ตัวเลือกพิมพ์ไฟล์บนบรรทัดเดียวแต่ละเพื่อความปลอดภัย -fตัวเลือกที่จะrmบอกว่ามันจะไม่สนใจไฟล์ที่ไม่มีอยู่จริงเมื่อlsผลตอบแทนอะไร
/path/to/your/logsมีไว้สำหรับคุณที่จะเข้าสู่เส้นทางที่ถูกต้อง ในการค้นหาข้อบกพร่องดำเนินการชิ้นส่วนls -t /path/...และls -t /path/... | tail -n +11เพียงอย่างเดียวและตรวจสอบว่าผลลัพธ์ที่ถูกต้อง
+ก่อนหมายเลข มันtailไม่ได้พิมพ์องค์ประกอบสุดท้าย n แต่องค์ประกอบทั้งหมดเริ่มต้นจาก n'th ฉันเช็คอินอีกครั้งและคำสั่งควรลบเฉพาะองค์ประกอบที่เก่ากว่า 10 ไฟล์ล่าสุดในทุกกรณี
lsพิมพ์ชื่อไฟล์ไม่ใช่เส้นทางดังนั้นคุณrm -fจะพยายามลบไฟล์ในไดเรกทอรีปัจจุบัน
เห็นได้ชัดว่าการแยกวิเคราะห์เป็นความชั่วร้าย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
-mtime 10 -deleteลบเฉพาะไฟล์ที่ถูกแก้ไขเมื่อ 10 วันก่อน ไฟล์ที่เก่ากว่าจะไม่ถูกลบ -mtime +11 -deleteจะลบไฟล์ที่ถูกแก้ไขตั้งแต่ 11 วันขึ้นไปและออกจากไฟล์บันทึก 10 วันล่าสุด
%pแทนเพื่อที่ว่าไฟล์จะได้รับเส้นทางที่สมบูรณ์ มิฉะนั้นการใช้งานไม่ได้ %Pprintfrm -rf
เครื่องมือเช่น logrotate ทำเพื่อคุณ มันทำให้การจัดการบันทึกง่ายขึ้นมาก คุณยังสามารถรวมรูทีนการล้างข้อมูลเพิ่มเติมตามที่รัศมีแนะนำได้
ฉันปรับเปลี่ยนแนวทางของ Isaacนิดหน่อย
ตอนนี้ใช้ได้กับเส้นทางที่ต้องการ:
ls -d -1tr /path/to/folder/* | head -n -10 | xargs -d '\n' rm -f
จากที่นี่ :
#! /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
ใน 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 อาจจะดีกว่าฉันแค่ต้องการแก้ไขคำตอบที่เกี่ยวข้องกับเชลล์ผิด
ไม่แน่ใจว่าจะช่วยใครได้ แต่เพื่อหลีกเลี่ยงปัญหาที่อาจเกิดขึ้นกับตัวอักษร wonky ฉันเพิ่งlsทำการเรียงลำดับ แต่ใช้ไฟล์inodeสำหรับการลบ
สำหรับไดเรกทอรีปัจจุบันจะเก็บ 10 ไฟล์ล่าสุดตามเวลาการแก้ไข
ls -1tri | awk '{print $1}' | head -n -10 | xargs -n1 -t -Iinode find . -inum inode -exec rm -i {} \;
ฉันต้องการโซลูชันที่สง่างามสำหรับ 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"
ฉันยอมรับว่า 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
ตามการตอบสนองของไอแซกฟรีแมน แต่ทำงานกับไดเรกทอรีใด ๆ
ls -1tr $PATH_TO_DELETE/* | head -n -10 | xargs -d '\n' rm -f --
คุณสามารถตั้งค่าคำนำหน้าเช่น $PATH_TO_DELETE/testFi*
หากคุณใช้*หลังจากPATH lsชื่อไฟล์สัมบูรณ์จะส่งออกอย่างน้อยใน "my" bash :)