整个剧本。

整个剧本。

我有一个脚本,当超过设定限制时,我想清除旧文件。

我有这个命令:

/bin/rm -f `/bin/ls -t $bkup_p/mysql.daily/*  2> /dev/null | /bin/awk 'NR>'5`

这是可行的,因为 $bkup_p 中可能有空格,我尝试将其更改为

/bin/rm -f `/bin/ls -t "$bkup_p/mysql.daily/*"  2> /dev/null | /bin/awk 'NR>'5`

但这是行不通的。它不显示有问题的文件,它只是空的

答案1

在根据修改时间过滤文件并对其执行命令时,Bash 并不是很方便。

我建议尝试 z-shell,所以首先运行zsh,然后

rm -i -- "$bkup_p"/mysql.daily/*(DN.Om[1,5])

这将删除给定目录中最旧的五个纯文件,我怀疑可能就是您想要实现的目标。显然,如果需要的话,最终会更改rm -irm -f

要删除五个最新文件,请执行以下操作

rm -i -- "$bkup_p"/mysql.daily/*(DN.om[1,5])

现在,它是如何工作的。里面的所有内容()都是所谓的 glob 限定符,它基本上根据您的需要过滤文件:

  • D包括点文件(以 开头的文件.
  • N如果没有匹配则不报告错误
  • .仅选择纯文件
  • om按修改时间排序(Om逆序排序)
  • [1,5]从列表中仅选择五个文件

我相信所有这些都应该适用于文件名中的特殊字符(空格、换行符等)

答案2

正如其他人所说,您不应该用于ls此目的。但是如果你的环境没有任何更明智的东西并且你了解注意事项, 你可能如果你的文件名是足够好:没有空格或者不可打印的字符,尤其是没有被 shell 解释为通配符的字符(至少?*[])。

使用 Perl 之类的东西对文件进行排序,或者将日期放在文件名中以便您可以依赖全局顺序会更好。


话虽如此:在您的第二个片段中,星号被引用,因此不会发生通配符。您会看到有关不存在的错误some dir/mysql.daily/*,但由于您将错误输出重定向走了,所以您没有看到。

带有空格的文件名会给您带来一个问题,即命令替换的输出沿空格分割,因此类似的内容some dir/foo将分为rm两部分:somedir/foo。希望它们都不存在,因为它们会被删除。

如果只有您的目录名称包含空格,您可以先cd进入它。或者,设置IFS为仅包含换行符(而不是默认的空格、制表符、换行符)。您提到了 NAS,那么您很可能拥有 busybox。这应该适用于 busybox 和 bash,并打印文件名,每行一个:

IFS=$'\n'
printf "%s\n" $( ls -t "$bkup_p/mysql.daily/"* | tail -n +6 )

如果您确定其工作正常,请替换printf "%s\n"rm以删除文件。

答案3

我建议不要解析 的输出,ls因为它不能正确格式化输出以通过管道传输到新命令,并且它存在可移植性问题。
我会尝试这样的事情

find $bkup_p/mysql.daily/ -type f -a -mtime +7 -a -name "*.sql" -a -exec rm -f {} +

笔记:

  • "*.sql"根据需要更改此设置
  • -mtime +7意味着*如果此文件在 7 天前被修改了更多 (+),显然也可以根据需要更改此文件

如果您想确保始终拥有 10 个最新文件 - 无论如何,(并且您有 GNU find)您可以尝试

find $bkup_p/mysql.daily/ -maxdepth 1 -type f -a -printf "%T+\t%p\n" | sort -r | sed -n '10,$p' | awk '{print $2}' | xargs rm -f

有关使用运算find符格式化输出的更多信息-printf,请参阅

man find | less '+/^\s*-printf'

答案4

不起作用的问题*是因为当您引用它时,它不会扩展。

将以下结果echo *与以下结果进行比较:echo "*"


可靠的解决方案是使用一个数组,每个数组位置上有一个文件。

如果你足够幸运并且你的发现支持这一点-printf

dir="$bkup_p/mysql.daily/"

find "$dir" -printf '%T@:%i\n'

所有文件名都将被避免。每个文件都是一行。一行仅包含数字、可选的点和冒号。

这可以很容易地排序:

find "$dir" -printf '%T@:%i\n' | sort -rn

最简单的数组是位置参数。
这会将目录中的所有文件设置为位置参数列表:

set -f; set -- $(find "$dir" -printf '%T@:%i\n' | sort -n )

set -f 将避免扩展任何也是通配符的文件名*。要避免(删除)前 6 个文件名,只需shift

shift 5

对其余文件执行您需要的操作:

for    f
do     rm -f "$(find "$dir" -inum "${f#*:}")"
done

整个剧本。

整个脚本(对于任何文件名都稳健)变为:

dir="$bkup_p/mysql.daily/"

set -f
set -- $(find "$dir" -type f -printf '%T@:%i\n'|sort -rn)
shift 5

for    f
do     rm -f "$(find "$dir" -inum "${f#*:}")"
done

相关内容