Score:18

Ubuntu ลบไฟล์ที่เก่าที่สุดในไดเร็กทอรีโดยอัตโนมัติเมื่อดิสก์มีความจุเกิน 90% ทำซ้ำจนกว่าความจุจะต่ำกว่า 80%

ธง bv

ฉันพบสคริปต์งาน cron ที่คล้ายกันสองสามตัว แต่ไม่มีอะไรตรงตามที่ฉันต้องการ และฉันไม่รู้เกี่ยวกับสคริปต์สำหรับ Linux มากพอที่จะลองแก้ไขโค้ดเมื่อมันมาถึงงานประเภทนี้ซึ่งอาจกลายเป็นหายนะได้

โดยพื้นฐานแล้วฉันมีกล้องไอพีที่บันทึก /home/ben/ftp/เฝ้าระวัง/ แต่ฉันต้องแน่ใจว่ามีพื้นที่ว่างเพียงพอในดิสก์เสมอ

ใครช่วยแนะนำฉันว่าฉันสามารถตั้งค่างาน cron เป็น:

ตรวจสอบว่า /dev/sbd/ มีกำลังการผลิตถึง 90% ถ้าเป็นเช่นนั้น ให้ลบไฟล์ที่เก่าที่สุดใน (และไฟล์ในโฟลเดอร์ย่อย) /home/ben/ftp/เฝ้าระวัง/ และทำซ้ำเช่นนี้จนกว่า /dev/sbd/ ความจุต่ำกว่า 80% ทำซ้ำทุกๆ 10 นาที

J... avatar
in flag
จะเกิดอะไรขึ้นถ้า `/dev/sdb` (หมายเหตุ: `sdb` != `sbd` - ระวังการพิมพ์ผิดในสคริปต์ของคุณ!) เต็ม >80% โดยไม่คำนึงถึงเนื้อหาของ `/home/ben/ftp/surveillance/` ? การดำเนินการนี้จะลบการบันทึกทั้งหมดของคุณ ทำให้คุณไม่มีอะไรเลย ดีกว่าที่จะให้กล้องวงจรปิดบันทึกลงในไดรฟ์ข้อมูลเฉพาะที่ไม่แชร์กับ (เช่น) ระบบปฏิบัติการของคุณหรือผู้ใช้รายอื่น ตามหลักการแล้ว กล้องควรจัดการสิ่งนี้ด้วยตัวเอง โดยตระหนักว่าไฟล์ใดเป็นของตนเอง และเขียนทับไฟล์ที่เก่าที่สุดของตัวเองเมื่อพื้นที่ไดรฟ์เฉพาะเต็ม
bv flag
หวัดดีเจ... ไดเร็กทอรี ftp ของฉันคือไดร์ฟภายนอกที่ติดตั้งอยู่ในโฮมไดเร็กทอรีของฉัน และตอนนี้มีไว้สำหรับการบันทึกด้วยกล้องโดยเฉพาะ ฉันไม่ได้สนใจที่จะเปลี่ยนโครงสร้างโฟลเดอร์ที่ก่อนหน้านี้เป็นดิสก์เฉพาะ กล้องยังอัปโหลดภาพนิ่ง .jpg ของการบันทึกทุกครั้ง ดังนั้นฉันจะตั้งค่า cron ใหม่เพื่อลบ .jpg ทั้งหมดเป็นระยะๆ
Score:33
ธง in

การเขียนบทแบบนี้สำหรับผู้คนมักจะทำให้ฉันประหม่าอยู่เสมอ เพราะหากเกิดข้อผิดพลาดขึ้น จะเกิดหนึ่งในสามสิ่งต่อไปนี้:

  1. ฉันจะเตะตัวเองสำหรับสิ่งที่อาจพิมพ์ผิดระดับ n00b
  2. ภัยคุกคามความตายจะมาหาฉันเพราะมีคนสุ่มสี่สุ่มห้าคัดลอก / วางโดยไม่:
    • พยายามทำความเข้าใจสคริปต์
    • การทดสอบสคริปต์
    • มีการสำรองข้อมูลที่เหมาะสม
  3. ทั้งหมดข้างต้น

ดังนั้น เพื่อลดความเสี่ยงทั้งสามประการ นี่คือชุดเริ่มต้นสำหรับคุณ:

#!/bin/sh
DIR=/home/ben/ftp/การเฝ้าระวัง
พระราชบัญญัติ=90
df -k $DIR | grep -vE '^ระบบไฟล์' | awk '{ พิมพ์ $5 " " $1 }' | ขณะอ่านเอาต์พุต
ทำ
  echo $เอาท์พุท
  usep=$(echo $output | awk '{ print $1}' | cut -d'%' -f1 )
  partition=$(echo $output | awk '{ พิมพ์ $2 }' )
  ถ้า [ $usep -ge $ACT ]; แล้ว
    echo "ไม่มีพื้นที่ว่าง \"$partition ($usep%)\" บน $(ชื่อโฮสต์) ณ วันที่ $(วันที่)"
    oldfile=$(ls -dltr $DIR/*.gz|awk '{ พิมพ์ $9 }' | หัว -1)
    echo "มาลบ \"$oldfile\" กันเถอะ ..."
  ไฟ
เสร็จแล้ว

สิ่งที่ควรทราบ:

  1. สคริปต์นี้ไม่ได้ลบอะไรเลย

  2. ผบ เป็นไดเร็กทอรีที่จะทำงานด้วย

  3. กระทำ เป็นเปอร์เซ็นต์ขั้นต่ำที่จำเป็นในการดำเนินการ

  4. เลือกไฟล์เดียวที่เก่าที่สุดสำหรับ "การลบ"

  5. คุณจะต้องการเปลี่ยน *.gz ด้วยประเภทไฟล์จริงของวิดีโอเฝ้าระวังของคุณ
    ไม่ได้ใช้ *.* หรือ * ด้วยตัวมันเอง!

  6. หากพาร์ติชั่นที่มี ผบ มีความจุมากกว่า กระทำคุณจะเห็นข้อความดังนี้:

    97% /dev/sda2
    พื้นที่ว่างหมด "/dev/sda2 (97%)" บน ubuntu-vm ณ วันพุธที่ 12 มกราคม 07:52:20 UTC 2022
    มาลบกันเถอะ "/home/ben/ftp/surveillance/1999-12-31-video.gz" ...
    

    อีกครั้งสคริปต์นี้ จะไม่ ลบอะไรก็ได้

  7. หากคุณพอใจกับผลลัพธ์ คุณสามารถแก้ไขสคริปต์ต่อไปเพื่อลบ/ย้าย/เก็บถาวรตามที่เห็นสมควร

ทดสอบบ่อยๆ ทดสอบให้ดี และจำไว้ว่า: เมื่อวาง rm ในสคริปต์ ไม่มีการเลิกทำ

ao flag
เป็นเรื่องโง่ที่จะไพพ์ `grep` เป็น `awk` คุณสามารถเพิ่ม `!/^Filesystem/` ต่อท้ายคำสั่ง awk หรือคุณสามารถบอก `df` ให้สร้างเฉพาะเอาต์พุตที่คุณต้องการ และใช้ `sed` เพื่อตัดส่วนหัวและเครื่องหมายเปอร์เซ็นต์: `usep=$(df --output=pcent $DIR | sed '1d;s/%/ /')`
Peter Cordes avatar
fr flag
`echo $output` ควรอ้างอิง `"$output"` เนื่องจากคุณไม่จำเป็นต้องแยกคำโดยเฉพาะ อาจเป็นเรื่องปกติ แต่แม้ในระบบปกติ สื่อที่ถอดเข้าออกได้บางส่วนจะติดตั้งบนเส้นทางที่มีช่องว่างในชื่อซึ่งอาจนำไปสู่ข้อความแสดงข้อผิดพลาดในทางปฏิบัติ ดังนั้น หลักทั่วไป ให้อ้างส่วนขยายตัวแปรเสมอ เว้นแต่ว่าคุณต้องการแยกคำโดยเฉพาะหรือเอฟเฟกต์อื่นๆ ที่อ้างบล็อก
ua flag
คล้ายกัน แต่ใช้ฟีเจอร์ `firstaction` ของ `logrotate`: https://serverfault.com/questions/372809/free-space-driven-log-rotation-on-linux
Eric Duminil avatar
us flag
@NickMatteo หากรหัสที่เกี่ยวข้องทำงานได้ดีและสามารถอ่านได้ การโต้แย้งว่ามันงี่เง่าเพราะมันอาจเขียนแตกต่างออกไปด้วยภาษาอายุ 45 ปีและอ่านไม่ค่อยออก ไพพ์ UNIX นั้นยอดเยี่ยมและอ่านง่าย ใครจะสนใจว่าคำสั่งสามารถเขียนด้วยไพพ์น้อยกว่าหนึ่งหรือสองตัวได้หรือไม่
ao flag
@EricDuminil: การใช้งานทั่วไปของ `grep 'PATTERN' | awk '{do stuff to matching lines}'` นั้นไร้สาระ เนื่องจากจุดประสงค์ทั้งหมดของ awk คือการทำสิ่งต่าง ๆ ในบรรทัดที่ตรงกัน และคุณสามารถเขียน `awk '/PATTERN/ {do stuff}'` ได้
Eric Duminil avatar
us flag
@NickMatteo: คุณสามารถใช้เครื่องมืออะไรก็ได้ที่คุณคุ้นเคย matigo ดูเหมือนจะมีความสุขกับ `grep ... | awk ...` คุณจะพอใจกับ `awk '/PATTERN/ {do stuff}` และฉันจะพอใจกับสคริปต์ Ruby หรือ Python สั้นๆ ตราบใดที่สคริปต์ยังใช้งานได้และอ่านได้ ไม่มีใครผิด และไม่มีคำสั่งใดโง่เขลา และแน่นอนว่าไม่โง่เขลา
cn flag
@EricDuminil พวกเขาอาจไม่งี่เง่าอย่างเป็นกลาง แต่มีข้อโต้แย้งว่าไซต์ถามตอบควรสอนผู้คนว่าคำสั่งทำงานอย่างไร การไพพ์ `awk` ทำให้ดูเหมือนว่าคำสั่งไม่สามารถจัดการได้ด้วยตัวเองนอกจากนี้ยังมีประโยชน์ในการไม่ใช้หลายคำสั่งผ่านไพพ์และทำให้กระบวนการช้าลง กล่าวโดยสังเขป มีหลักเกณฑ์ที่จะโต้แย้งว่าการใช้ `awk` ตามที่ตั้งใจจะใช้เป็นคำตอบที่ดีกว่า
bv flag
@matgio - ฉันไม่สามารถรับ `oldfile=$(ls -dltr $DIR/*.mp4|awk '{ print $9 }' | head -1)` ให้ใช้งานได้ แต่ฉันทำให้มันใช้งานได้ `oldfile=$( ค้นหา $DIR -name "*.mp4" -type f | sort | head -n 1)` หากมีเหตุผลใดที่ไม่ควรใช้วิธีของฉัน
in flag
@Beno â คุณได้รับข้อผิดพลาดกับคำสั่งแรกหรือไม่? ไม่ว่าจะด้วยวิธีใด หาก `find` จะให้สิ่งที่คุณต้องการ คุณสามารถใช้มันได้ตามสบาย สคริปต์เป็นเพียง "ชุดเริ่มต้น" เพื่อให้คุณดำเนินการเบื้องต้นบางอย่างได้
Score:12
ธง kz

ฉันจะใช้ Python สำหรับงานดังกล่าว อาจนำไปสู่รหัสมากกว่าโซลูชัน bash บริสุทธิ์ แต่:

  • การทดสอบ (IMO) ง่ายกว่า เพียงแค่ใช้ pytest หรือ รวมกัน โมดูล
  • มันสามารถอ่านได้สำหรับผู้ที่ไม่ใช่ Linux (ยกเว้นไฟล์ get_device ฟังก์ชันที่เป็นเฉพาะของ Linux...)
  • เริ่มต้นได้ง่ายขึ้น (IMO อีกครั้ง)
  • ถ้าคุณต้องการส่งอีเมลบ้าง เพื่อกระตุ้นการกระทำใหม่ ? สามารถเพิ่มสคริปต์ได้อย่างง่ายดายด้วยภาษาโปรแกรมเช่น Python

ตั้งแต่ Python 3.3 ปิด โมดูลมาพร้อมกับฟังก์ชันชื่อ disk_usage. สามารถใช้เพื่อรับการใช้งานดิสก์ตามไดเร็กทอรีที่กำหนด

ปัญหาเล็กน้อยคือฉันไม่รู้วิธีรับชื่อดิสก์อย่างง่าย IE /dev/sdbแม้ว่าจะเป็นไปได้ที่จะได้รับการใช้งานดิสก์ (โดยใช้ไดเร็กทอรีใด ๆ ที่เมาท์บน /dev/sdbในกรณีของฉัน $บ้าน ตัวอย่างเช่น). ฉันเขียนฟังก์ชันที่เรียกว่า get_device เพื่อจุดประสงค์นี้.

#!/usr/bin/env python3
argparse นำเข้า
จาก os.path นำเข้า getmtime
จากการปิดการนำเข้า disk_usage, rmtree
จากทางออกการนำเข้า sys
จากเส้นทางนำเข้า pathlib
จากการพิมพ์ import Iterator, Tuple


def get_device (เส้นทาง: เส้นทาง) -> str:
    """ค้นหาการเมานต์สำหรับไดเร็กทอรีที่กำหนด สิ่งนี้จำเป็นสำหรับการบันทึกเท่านั้น"""
    # อ่าน /etc/mtab เพื่อเรียนรู้เกี่ยวกับจุดเชื่อมต่อ
    mtab_entries = Path("/etc/mtab").read_text().splitlines()
    # สร้าง dict ของจุดเชื่อมต่อและอุปกรณ์
    mount_points = dict([list(reversed(line.split(" ")[:2])) for line in mtab_entries])
    # ค้นหาจุดเชื่อมต่อของเส้นทางที่กำหนด
    ในขณะที่ path.resolve(True).as_posix() ไม่อยู่ใน mount_points:
        เส้นทาง = เส้นทางพาเรนต์
    # คืนอุปกรณ์ที่เกี่ยวข้องกับจุดเมานต์
    ส่งคืน mount_points[path.as_posix()]


def get_directory_and_device (เส้นทาง: str) -> ทูเปิล [str, เส้นทาง]:
    """ออกจากกระบวนการหากไม่มีไดเร็กทอรี"""
    fs_path = เส้นทาง (เส้นทาง)
    #เส้นทางต้องมี
    ถ้าไม่ใช่ fs_path.exists():
        พิมพ์ (f"ข้อผิดพลาด: ไม่มีไดเรกทอรีดังกล่าว: {เส้นทาง}")
        ทางออก(1)
    # และเส้นทางต้องเป็นไดเร็กทอรีที่ถูกต้อง
    ถ้าไม่ใช่ fs_path.is_dir():
        พิมพ์(f"เส้นทางต้องเป็นไดเรกทอรีและไม่ใช่ไฟล์: {เส้นทาง}")
        ทางออก(1)
    #รับเครื่อง
    อุปกรณ์ = get_device (fs_path)

    ส่งคืนอุปกรณ์ fs_path


def get_disk_usage (เส้นทาง: เส้นทาง) -> ลอย:
    # shutil.disk_usage รองรับเส้นทางเช่นวัตถุจึงไม่จำเป็นต้องส่งไปยังสตริง
    การใช้งาน = disk_usage (เส้นทาง)
    # รับการใช้ดิสก์เป็นเปอร์เซ็นต์
    ส่งคืนการใช้งานที่ใช้ / การใช้งานรวม * 100


def remove_file_or_directory (เส้นทาง: เส้นทาง) -> ไม่มี:
    """ลบเส้นทางที่กำหนดซึ่งอาจเป็นไดเร็กทอรีหรือไฟล์"""
    #ลบไฟล์
    ถ้า path.is_file():
        เส้นทาง.ยกเลิกการเชื่อมโยง()
    # ลบแผนผังไดเร็กทอรีแบบวนซ้ำ
    ถ้า path.is_dir():
        rmtree (เส้นทาง)


def find_oldest_files(
    เส้นทาง: เส้นทาง รูปแบบ: str = "*" เกณฑ์: int = 80
) -> ตัววนซ้ำ [เส้นทาง]:
    """วนซ้ำไฟล์หรือไดเร็กทอรีที่อยู่ในไดเร็กทอรีซึ่งตรงกับรูปแบบที่กำหนด"""
    # รายชื่อไฟล์ในไดเร็กทอรีที่ได้รับเป็นอาร์กิวเมนต์และจัดเรียงตามอายุ
    ไฟล์ = เรียงลำดับ (path.glob (รูปแบบ), คีย์ = getmtime)
    # เส้นทางไฟล์ผลตอบแทนจนกว่าการใช้งานจะต่ำกว่าเกณฑ์
    สำหรับไฟล์ในไฟล์:
        การใช้งาน = get_disk_usage (เส้นทาง)
        ถ้าการใช้งาน <เกณฑ์:
            หยุดพัก
        ไฟล์ผลตอบแทน


def check_and_clean(
    เส้นทาง: str,
    เกณฑ์: int = 80,
    ลบ: บูล = เท็จ
) -> ไม่มี:
    """ฟังก์ชั่นหลัก"""
    อุปกรณ์ fspath = get_directory_and_device (เส้นทาง)
    # shutil.disk_usage รองรับเส้นทางเช่นวัตถุจึงไม่จำเป็นต้องส่งไปยังสตริง
    การใช้งาน = disk_usage (เส้นทาง)
    #ดำเนินการหากจำเป็น
    ถ้าการใช้งาน > เกณฑ์:
        พิมพ์(
            f"การใช้ดิสก์มากกว่าเกณฑ์: {usage:.2f}% > {threshold}% ({device})"
        )
    # วนซ้ำไฟล์ที่จะลบ
    สำหรับไฟล์ใน find_oldest_files(fspath, "*", threshold):
        พิมพ์ (ฉ "การลบไฟล์ {ไฟล์}")
        ถ้าลบ:
            remove_file_or_directory (ไฟล์)


def main() -> ไม่มี:

    พาร์เซอร์ = argparse.ArgumentParser(
        Description="ล้างไฟล์เก่าเมื่อการใช้งานดิสก์เกินขีดจำกัด"
    )

    parser.add_argument(
        "path", help="เส้นทางไดเร็กทอรีที่ควรกำจัดไฟล์", type=str
    )
    parser.add_argument(
        "--เกณฑ์",
        "-t",
        metavar = "T",
        help="เกณฑ์การใช้งานเป็นเปอร์เซ็นต์",
        พิมพ์=int,
        ค่าเริ่มต้น=80,
    )
    parser.add_argument(
        "--ลบ",
        "--rm",
        help="ไฟล์จะไม่ถูกลบเว้นแต่จะระบุตัวเลือก --removed หรือ --rm",
        การดำเนินการ = "store_true",
        ค่าเริ่มต้น = เท็จ
    )

    หาเรื่อง = parser.parse_args()

    check_and_clean(
        args.path,
        threshold=args.threshold,
        เอาออก = args.remove,
    )


ถ้า __name__ == "__main__":
    หลัก()

หากคุณต้องการจัดการงานหลายอย่างโดยใช้ CRON อาจคุ้มค่าที่จะรวมโค้ด Python ไว้เป็นไลบรารี และนำโค้ดนี้กลับมาใช้ซ้ำกับหลายๆ งาน

แก้ไข: ในที่สุดฉันก็เพิ่มส่วน CLI ในสคริปต์ ฉันคิดว่าฉันจะใช้มันเอง

qwr avatar
kr flag
qwr
fwiw คุณสามารถส่งอีเมลจากบรรทัดคำสั่ง
gcharbon avatar
kz flag
ฉันไม่ได้บอกว่าไม่สามารถทำได้ใน CLI ฉันกำลังบอกว่า OP ไม่คุ้นเคยกับ bash และเขาอาจคิดว่ามันง่ายกว่าที่จะทำใน Python
bv flag
ขอบคุณสำหรับโพสต์ที่ครอบคลุม! ฉันชอบแนวทางที่อ่านได้ง่ายกว่า แต่น่าเสียดายที่ฉันไม่คุ้นเคยกับไฟธอนเช่นกัน แต่คุณทำให้ฉันรู้ว่าฉันสามารถทำได้ด้วย php ซึ่งฉันสบายใจกว่ามาก
Clumsy cat avatar
cn flag
+1 สำหรับสิ่งที่ทดสอบได้ง่ายขึ้น ฉันต้องการการทดสอบหน่วยสำหรับสคริปต์เช่นนี้
Score:1
ธง tj

ตรวจสอบว่า /dev/sbd/ มีกำลังการผลิตถึง 90% ถ้าเป็นเช่นนั้น ให้ลบไฟล์ที่เก่าที่สุดใน (และไฟล์ในโฟลเดอร์ย่อย) /home/ben/ftp/เฝ้าระวัง/ และทำซ้ำเช่นนี้จนกว่า /dev/sbd/ ความจุต่ำกว่า 80% ทำซ้ำทุกๆ 10 นาที

สคริปต์ด้านล่างจะทำเช่นนั้น (โดยที่คุณเพิ่มลงในไฟล์ crontab ให้ทำงานทุก ๆ 10 นาที) ตรวจสอบให้แน่ใจเป็นพิเศษว่านี่คือสิ่งที่คุณต้องการทำจริง ๆ เนื่องจากสิ่งนี้สามารถลบออกได้ง่าย ทั้งหมด ไฟล์ใน /home/ben/ftp/เฝ้าระวัง/ หากดิสก์ของคุณเต็มนอกไดเร็กทอรีนี้

#!/bin/sh
ไดเร็กทอรี = '/ home / ben / ftp / การเฝ้าระวัง'
max_usage=90
goal_usage=80
[ -d "ไดเรกทอรี $" ] || ทางออก 1
[ "$max_usage" -gt "$goal_usage" ] || ทางออก 1
[ "$( df --output=pcent $ไดเรกทอรี | \
    grep -Ewo '[0-9]+' )" -ge "$max_usage" ] || ออก 0
dev_used="$( df -B 1K --output=us $directory | \
    grep -Ewo '[0-9]+' )"
goal_usage="$( พิมพ์f "%.0f" \
    $( echo ".01 * $goal_usage * \
    $( df -B 1K --output=size $ไดเรกทอรี | \
        grep -Ewo '[0-9]+' )" | bc ) )"
echo "$( find $directory -type f -printf '%Ts,%k,\047%p\047\n' )" | \
    จัดเรียง -k1 | \
        awk -F, -v เป้าหมาย="$(($dev_used-$goal_usage))" '\
            (ผลรวม+$2)>เป้าหมาย{printf "%s ",$3; ทางออก} \
            (ผลรวม+$2)<=เป้าหมาย{printf "%s ",$3}; {ผลรวม+=$2}' | \
                xargs rm

สคริปต์นี้ทำงานอย่างไร:

3 บรรทัดแรกหลัง shebang คือตัวแปรตามพารามิเตอร์ของคุณ:

  • ไดเรกทอรี เป็นพาธเต็มไปยังไดเร็กทอรีหลักที่มีไฟล์และไดเร็กทอรีย่อยที่คุณต้องการลบไฟล์เก่า (เช่น /home/ben/ftp/เฝ้าระวัง). เครื่องหมายอัญประกาศรอบค่านี้ไม่จำเป็นเว้นแต่พาธจะมีช่องว่าง
  • max_usage คือเปอร์เซ็นต์ของความจุของดิสก์ที่จะทริกเกอร์การดำเนินการลบไฟล์เก่า (กล่าวคือ 90 เปอร์เซ็นต์)
  • เป้าหมาย_การใช้งาน คือเปอร์เซ็นต์ของความจุดิสก์ที่คุณต้องการได้รับหลังจากลบไฟล์เก่า (เช่น 80 เปอร์เซ็นต์)

โปรดทราบว่าค่าของ max_usage และ เป้าหมาย_การใช้งาน ต้องเป็น จำนวนเต็ม.

[ -d "ไดเรกทอรี $" ] || ทางออก 1
  • ตรวจสอบว่า ไดเรกทอรี มีอยู่ มิฉะนั้นสคริปต์จะสิ้นสุดและออกด้วยสถานะ 1
[ "$max_usage" -gt "$goal_usage" ] || ทางออก 1
  • ตรวจสอบว่า max_usage มีค่ามากกว่า เป้าหมาย_การใช้งานมิฉะนั้นสคริปต์จะสิ้นสุดและออกด้วยสถานะ 1
[ "$( df --output=pcent $ไดเรกทอรี | \
    grep -Ewo '[0-9]+' )" -ge "$max_usage" ] || ออก 0
  • รับเปอร์เซ็นต์ความจุของดิสก์ปัจจุบันที่ใช้และตรวจสอบว่าตรงตามหรือเกินเกณฑ์ที่กำหนดโดย max_usage. หากไม่มี ก็ไม่จำเป็นต้องดำเนินการเพิ่มเติม ดังนั้นสคริปต์จะสิ้นสุดและออกด้วยสถานะ 0
dev_used="$( df -B 1K --output=us $directory | \
    grep -Ewo '[0-9]+' )"
  • รับความจุของดิสก์ในปัจจุบันเป็นกิโลไบต์ที่ใช้
goal_usage="$( พิมพ์f "%.0f" \
    $( echo ".01 * $goal_usage * \
    $( df -B 1K --output=size $ไดเรกทอรี | \
        grep -Ewo '[0-9]+' )" | bc ) )"
  • แปลง เป้าหมาย_การใช้งาน ตัวแปรเป็นกิโลไบต์ (เราต้องการค่านี้ต่อไป)
ค้นหา $directory -type f -printf '%Ts,%k,\047%p\047\n'
  • ค้นหาไฟล์ทั้งหมดใน ไดเรกทอรี (และในไดเร็กทอรีย่อยทั้งหมด) และสร้างรายการไฟล์เหล่านี้ หนึ่งรายการต่อบรรทัด โดยจัดรูปแบบเป็น การประทับเวลา, ขนาดเป็นกิโลไบต์, 'เต็ม/พาธ/ถึง/ไฟล์'. โปรดทราบว่า 'เต็ม/เส้นทาง/ถึง/ไฟล์' อยู่ในเครื่องหมายอัญประกาศเดี่ยว ดังนั้นการเว้นวรรคในชื่อไฟล์หรือไดเร็กทอรีจะไม่ทำให้เกิดปัญหาในภายหลัง
เรียงลำดับ -k1
  • เรียงลำดับก่อนหน้านี้ เสียงสะท้อน'd รายการไฟล์ตามเวลาประทับ (เก่าที่สุดก่อน)
awk -F, -v เป้าหมาย="$(($dev_used-$goal_usage))"
  • อึดอัด สร้างตัวแปรภายใน เป้าหมาย นั่นเท่ากับผลต่างระหว่าง dev_used และ เป้าหมาย_การใช้งาน - และนี่คือมูลค่ากิโลไบต์ทั้งหมดของไฟล์ที่ต้องลบออกเพื่อให้เปอร์เซ็นต์ความจุของดิสก์ลดลงเหลือ เป้าหมาย_การใช้งาน ตั้งไว้ที่จุดเริ่มต้นของสคริปต์
(ผลรวม+$2)>เป้าหมาย{printf "%s ",$3; ทางออก} \
(ผลรวม+$2)<=เป้าหมาย{printf "%s ",$3}; {ผลรวม+=$2}'
  • อึดอัด (ต่อ) เริ่มประมวลผลรายการโดยเก็บผลรวมของค่าฟิลด์ 2 ไว้ (ขนาดเป็นกิโลไบต์) และฟิลด์การพิมพ์ 3 ค่า ('เต็ม/เส้นทาง/ถึง/ไฟล์') ไปยังสตริงที่คั่นด้วยช่องว่างจนกว่าผลรวมของกิโลไบต์จากฟิลด์ 2 จะมากกว่า เป้าหมายซึ่ง ณ จุดนั้น อึดอัด หยุดการประมวลผลบรรทัดเพิ่มเติม
xargs rm
  • สตริงของค่า 'full/path/to/file' จาก อึดอัด ถูกส่งไปที่ xargs ซึ่งเรียกใช้ rm คำสั่งโดยใช้สตริงเป็นอาร์กิวเมนต์ สิ่งนี้จะลบไฟล์เหล่านั้น

โพสต์คำตอบ

คนส่วนใหญ่ไม่เข้าใจว่าการถามคำถามมากมายจะปลดล็อกการเรียนรู้และปรับปรุงความสัมพันธ์ระหว่างบุคคล ตัวอย่างเช่น ในการศึกษาของ Alison แม้ว่าผู้คนจะจำได้อย่างแม่นยำว่ามีคำถามกี่ข้อที่ถูกถามในการสนทนา แต่พวกเขาไม่เข้าใจความเชื่อมโยงระหว่างคำถามและความชอบ จากการศึกษาทั้ง 4 เรื่องที่ผู้เข้าร่วมมีส่วนร่วมในการสนทนาด้วยตนเองหรืออ่านบันทึกการสนทนาของผู้อื่น ผู้คนมักไม่ตระหนักว่าการถามคำถามจะมีอิทธิพลหรือมีอิทธิพลต่อระดับมิตรภาพระหว่างผู้สนทนา