这个 shell 命令删除除最后一个 X 目录之外的所有目录安全吗?
Is this shell command to delete all but last X directories safe?
我已经看到很多关于文件名中带有滑稽字符的危险的警告,这些警告会在 shell 脚本中造成严重破坏。
我搜索了 SO 并看到了 xargs
和 -exec rm -rf {} \;
以及 "don't use ls
for scripting" 的数十种变体,并且我想出了我 认为的 是 "safe" 到 运行。
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
ed 而 mtime/ctime 不匹配。
我认为我上面的 shell 命令应该做到这一点,但我只是想仔细检查它不会炸毁我的服务器,如果其中一个目录包含 *
或.
什么的。
这是安全的,因为:
- 没有 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 --
None 特别是 可移植 -- 原始代码和上述建议都需要对 find
进行非 POSIX 扩展, sort
, head
和 xargs
;并且在 Windows 文件系统(其中 :
被保留)上不允许命名约定本身——但是如果你在 UNIXy 平台上 运行 使用现代 GNU 工具链,这我觉得不错。
我已经看到很多关于文件名中带有滑稽字符的危险的警告,这些警告会在 shell 脚本中造成严重破坏。
我搜索了 SO 并看到了 xargs
和 -exec rm -rf {} \;
以及 "don't use ls
for scripting" 的数十种变体,并且我想出了我 认为的 是 "safe" 到 运行。
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
ed 而 mtime/ctime 不匹配。
我认为我上面的 shell 命令应该做到这一点,但我只是想仔细检查它不会炸毁我的服务器,如果其中一个目录包含 *
或.
什么的。
这是安全的,因为:
- 没有 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 --
None 特别是 可移植 -- 原始代码和上述建议都需要对 find
进行非 POSIX 扩展, sort
, head
和 xargs
;并且在 Windows 文件系统(其中 :
被保留)上不允许命名约定本身——但是如果你在 UNIXy 平台上 运行 使用现代 GNU 工具链,这我觉得不错。