这个shell命令是否可以删除除最后X个目录以外的所有目录?

时间:2017-05-13 23:00:50

标签: bash delete-file rm

我已经看到很多警告,反对文件名的危险,有趣的角色在shell脚本中造成严重破坏。

我已经搜索了SO并看到了xargs-exec rm -rf {} \;的几十种变体,以及“不使用ls编写脚本”而且我想出了我< em>认为是“安全”的。

find /path/to/dir -mindepth 1 -maxdepth 1 -type d -print0 | sort -z | head -z -n -10 | xargs -r0 rm -rf

我有一个以这种格式装满子目录的目录:

# find /srv/mywebsite/releases -mindepth 1 -maxdepth 1 -type d | sort
/srv/mywebsite/releases/2017-01-01T01:43:23Z
/srv/mywebsite/releases/2017-01-01T02:09:44Z
/srv/mywebsite/releases/2017-01-01T02:20:06Z
...
/srv/mywebsite/releases/2017-04-22T01:34:45Z
/srv/mywebsite/releases/2017-04-30T03:24:19Z
/srv/mywebsite/releases/2017-05-02T01:48:39Z

我想删除除最后10个之外的所有内容,按目录名称中的日期排序,目录mod / create-time。这只是一个预防措施,以防其中一个目录被touch编辑并且mtime / ctime不匹配。

我认为我上面的shell命令应该就是这样,但我只想仔细检查一下如果其中一个dirs包含*.或者它将不会炸毁我的服务器东西。

1 个答案:

答案 0 :(得分:3)

这是安全的,因为:

  • 没有对名称进行任何shell评估。这特别包括glob扩展,因此包含*的名称不会产生额外的rm参数。
  • 由于所有名称都以/path/to/dir为前缀,因此我们不必担心将前导符号解释为选项。 (在确实有此问题的情况下,xargs -r0 rm -rf --是合适的;对于POSIX utility syntax guideline #10,传递字符串--可确保将所有后续参数解析为位置)。
  • 由于所有名称都与NUL分开,并且NUL不能存在于名称中,因此我们无法在rm的多个参数中生成单个名称结果。 (编写得不好的脚本通常会对换行做出类似的假设,但这种假设是没有根据的。)

因为您依赖于以特定格式表示UTC时间戳的名称(以及新名称继续匹配该格式以便可以与旧名称进行适当比较),您可能需要添加适当的过滤器,使完整的命令类似于:

find /path/to/dir -mindepth 1 -maxdepth 1 -type d \
  -regextype posix-extended \
  -regex '.*/[[:digit:]]{4}-[[:digit:]]{2}-[[:digit:]]{2}T[[:digit:]]{2}:[[:digit:]]{2}:[[:digit:]]{2}Z$' \
  -print0 | sort -z | head -z -n -10 | xargs -r0 rm -rf --

这些都不是特别可移植 - 原始代码和上述建议都要求对findsorthead进行非POSIX扩展, xargs;并且在Windows文件系统(其中保留:)上不允许使用命名约定 - 但如果您在UNIXy平台上运行现代GNU工具链,这对我来说很好。