我发现了一些类似的 cron 作业脚本,但没有完全了解我需要它们的方式,而且我对 Linux 脚本了解不够,无法在涉及此类作业时尝试修改代码,这可能会带来灾难性的后果。
本质上,我有可以记录的网络摄像机/home/ben/ftp/surveillance/,但我需要确保磁盘上始终有足够的空间来执行此操作。
有人可以指导我如何设置 cron 作业来:
检查是否/dev/sbd/已达到 90% 容量。如果是这样,则删除其中最旧的文件(以及子文件夹中的文件)/home/ben/ftp/surveillance/并重复此操作,直到/dev/sbd/容量低于 80% 每 10 分钟重复一次。
mat*_*igo 37
为人们编写此类脚本总是让我感到紧张,因为如果出现任何问题,就会发生以下三种情况之一:
\n因此,为了降低这三者的风险,这里为您提供了一个入门套件:
\n#!/bin/sh\nDIR=/home/ben/ftp/surveillance\nACT=90\ndf -k $DIR | grep -vE '^Filesystem' | awk '{ print $5 " " $1 }' | while read output;\ndo\n echo $output\n usep=$(echo $output | awk '{ print $1}' | cut -d'%' -f1 )\n partition=$(echo $output | awk '{ print $2 }' )\n if [ $usep -ge $ACT ]; then\n echo "Running out of space \\"$partition ($usep%)\\" on $(hostname) as on $(date)"\n oldfile=$(ls -dltr $DIR/*.gz|awk '{ print $9 }' | head -1)\n echo "Let's Delete \\"$oldfile\\" ..."\n fi\ndone\nRun Code Online (Sandbox Code Playgroud)\n注意事项:
\n该脚本不会删除任何内容
\nDIR是要使用的目录
ACT是采取行动所需的最低百分比
仅选择一个文件 \xe2\x80\x93\xc2\xa0 最旧的 \xe2\x80\x93\xc2\xa0 进行“删除”
\n您需要替换*.gz为监控视频的实际文件类型。
请勿使用*.*或*单独使用!
如果包含的分区的DIR容量大于ACT,您将看到如下消息:
97% /dev/sda2\nRunning out of space "/dev/sda2 (97%)" on ubuntu-vm as on Wed Jan 12 07:52:20 UTC 2022\nLet's Delete "/home/ben/ftp/surveillance/1999-12-31-video.gz" ...\nRun Code Online (Sandbox Code Playgroud)\n同样,该脚本不会删除任何内容。
\n如果您对输出感到满意,那么您可以继续修改脚本以根据需要删除/移动/存档
\n经常测试。好好测试一下。请记住:放入rm脚本时,无法撤消。
gch*_*bon 13
我会使用 Python 来完成这样的任务。它可能会比纯 bash 解决方案产生更多的代码,但是:
pytest或unitest模块get_deviceLinux 特定的功能......)从 Python 3.3 开始,shutil模块附带了一个名为 的函数disk_usage。它可用于根据给定目录获取磁盘使用情况。
小问题是我不知道如何轻松获取磁盘 IE 的名称/dev/sdb,即使可以获取其磁盘使用情况(使用安装在 上的任何目录/dev/sdb,$HOME例如在我的情况下)。get_device我为此目的编写了一个函数。
#!/usr/bin/env python3
import argparse
from os.path import getmtime
from shutil import disk_usage, rmtree
from sys import exit
from pathlib import Path
from typing import Iterator, Tuple
def get_device(path: Path) -> str:
"""Find the mount for a given directory. This is needed only for logging purpose."""
# Read /etc/mtab to learn about mount points
mtab_entries = Path("/etc/mtab").read_text().splitlines()
# Create a dict of mount points and devices
mount_points = dict([list(reversed(line.split(" ")[:2])) for line in mtab_entries])
# Find the mount point of given path
while path.resolve(True).as_posix() not in mount_points:
path = path.parent
# Return device associated with mount point
return mount_points[path.as_posix()]
def get_directory_and_device(path: str) -> Tuple[str, Path]:
"""Exit the process if directory does not exist."""
fs_path = Path(path)
# Path must exist
if not fs_path.exists():
print(f"ERROR: No such directory: {path}")
exit(1)
# And path must be a valid directory
if not fs_path.is_dir():
print(f"Path must be a directory and not a file: {path}")
exit(1)
# Get the device
device = get_device(fs_path)
return device, fs_path
def get_disk_usage(path: Path) -> float:
# shutil.disk_usage support Path like objects so no need to cast to string
usage = disk_usage(path)
# Get disk usage in percentage
return usage.used / usage.total * 100
def remove_file_or_directory(path: Path) -> None:
"""Remove given path, which can be a directory or a file."""
# Remove files
if path.is_file():
path.unlink()
# Recursively delete directory trees
if path.is_dir():
rmtree(path)
def find_oldest_files(
path: Path, pattern: str = "*", threshold: int = 80
) -> Iterator[Path]:
"""Iterate on the files or directories present in a directory which match given pattern."""
# List the files in the directory received as argument and sort them by age
files = sorted(path.glob(pattern), key=getmtime)
# Yield file paths until usage is lower than threshold
for file in files:
usage = get_disk_usage(path)
if usage < threshold:
break
yield file
def check_and_clean(
path: str,
threshold: int = 80,
remove: bool = False,
) -> None:
"""Main function"""
device, fspath = get_directory_and_device(path)
# shutil.disk_usage support Path like objects so no need to cast to string
usage = disk_usage(path)
# Take action if needed
if usage > threshold:
print(
f"Disk usage is greather than threshold: {usage:.2f}% > {threshold}% ({device})"
)
# Iterate over files to remove
for file in find_oldest_files(fspath, "*", threshold):
print(f"Removing file {file}")
if remove:
remove_file_or_directory(file)
def main() -> None:
parser = argparse.ArgumentParser(
description="Purge old files when disk usage is above limit."
)
parser.add_argument(
"path", help="Directory path where files should be purged", type=str
)
parser.add_argument(
"--threshold",
"-t",
metavar="T",
help="Usage threshold in percentage",
type=int,
default=80,
)
parser.add_argument(
"--remove",
"--rm",
help="Files are not removed unless --removed or --rm option is specified",
action="store_true",
default=False,
)
args = parser.parse_args()
check_and_clean(
args.path,
threshold=args.threshold,
remove=args.remove,
)
if __name__ == "__main__":
main()
Run Code Online (Sandbox Code Playgroud)
如果您需要使用 CRON 编排许多任务,则可能值得将一些 Python 代码放在一起作为库,并在许多任务中重用此代码。
编辑:我终于在脚本中添加了 CLI 部分,我想我自己会使用它