为什么 crontab 作业中的 * 被文件名替换

为什么 crontab 作业中的 * 被文件名替换

我的干净的 docker 日志脚本如下(CentOS 7):

#!/usr/bin/env bash

set -uex

echo "======== start clean docker containers logs ========"  
logs=$(find /var/lib/docker/ -type f -name *.log -size +25M)  
for log in $logs  
  do  
    echo "clean logs : $log"  
    cat /dev/null > $log  
  done  
logsrm=$(find /var/lib/docker/ -mtime +7 -name *.log -type f)  
for logm in $logsrm  
  do  
    echo "delete logs : $logm"  
    cat /dev/null > $logm
  done
echo "======== end clean docker containers logs ========"

当我使用 crontab 执行它时:

*/1 * * * * root /data/scripts/docker-clean.sh >> $HOME/cron.log 2>&1

输出日志如下:

[root@uat-k8s-01 ~]# tail -f cron.log
++ find /var/lib/docker/ -type f -name cron.log cront.log -size +25M
find: paths must precede expression: cront.log
Usage: find [-H] [-L] [-P] [-Olevel] [-D help|tree|search|stat|rates|opt|exec] [path...] [expression]
+ logs=
+ echo '======== start clean docker containers logs ========'
======== start clean docker containers logs ========
++ find /var/lib/docker/ -type f -name cron.log cront.log -size +25M
find: paths must precede expression: cront.log
Usage: find [-H] [-L] [-P] [-Olevel] [-D help|tree|search|stat|rates|opt|exec] [path...] [expression]
+ logs=

我应该怎么做才能让它正常工作?

答案1

正如我在回答中提到的你之前的问题,必须引用该模式*.log以阻止 shell 在调用之前将模式扩展为当前目录中的名称find

除此之外,不要循环遍历find(参见例如“为什么循环查找的输出是不好的做法?”)。

在你的情况下,循环

logs=$(find /var/lib/docker/ -type f -name *.log -size +25M)  
for log in $logs  
  do  
    echo "clean logs : $log"  
    cat /dev/null > $log  
  done  

可以重写为

find /var/lib/docker -type f -name '*.log' -size +25M -exec sh -c '
for log
  do
    echo "clean logs : $log"  
    cat /dev/null > "$log"
  done' sh {} +

或者,如果您有 GNUtruncate实用程序,

find /var/lib/docker -type f -name '*.log' -size +25M \
    -exec echo "clean logs: " {} \; -exec truncate --size=0 {} +

或者,使用 GNU find

find /var/lib/docker -type f -name '*.log' -size +25M \
    -printf 'clean logs: %p\n' -exec truncate --size=0 {} +

第二个循环可以用同样的方式重写,或者你可以将它们组合起来:

find /var/lib/docker -type f -name '*.log' \
    \( \( -size +25M -printf 'clean logs: %p\n'  \) -o \
       \( -mtime +7  -printf 'delete logs: %p\n' \) \) -exec truncate --size=0 {} +

也可以看看 ”了解“find”的 -exec 选项”。

由于您的脚本仅使用标准sh语法,因此您还可以将第一行更改为#!/bin/sh.

答案2

使用的两行find需要更改,例如,

find /var/lib/docker/ -type f -name *.log -size +25M

问题是未引用的*.log.将其放在单引号中,'*.log'.

原因是当它不被引用时,shell 可以访问它并将其扩展以匹配当前目录中的文件。如果您有两个或更多日志文件,您将得到类似的信息,这将触发find您所看到的错误

find /var/lib/docker/ -type f -name aa.log bb.log cc.log -size +25M

相关内容