如何避免在 bash 脚本中使用 rm -rf?

GP9*_*P92 2 shell-script rm

rm -rf由于未设置的变量,我曾经有过使用 的危险经历。从那时起,我在撰写涉及rm -rf. 多次交叉检查拼写错误、空格等。

到目前为止,我一直尽可能遵循这些做法:

  • 使用非 root 用户。
  • 避免使用*和使用更具体的文件路径。
  • 避免使用变量作为目录名称。

所以我想知道是否有一些标准/推荐的做法或方法或脚本可以使用rm -rf,特别*是如果脚本中存在一些手动错误,它不会具有破坏性。

更新:

此处创建了用于清空给定目录的正在进行的 bash 实用程序: https: //github.com/g1patnaik/system_utilities/tree/dev/empty_directory

Kus*_*nda 6

我不认为这个问题是关于避免rm -rf,而是关于避免最终进入操作不安全的状态或以可能产生不确定后果的方式使用它。当涉及到拼写错误时,您可以使用诸如shellcheck和 设置某些 shell 变量(例如failglobin bash、 和nounsetexample)之类的工具来捕获其中一些错误。尽管如此,最终还是要养成在运行代码之前阅读代码并在一次性或备份数据上进行测试的习惯。

我不认为让事情变得太复杂有什么用。如果要删除所有目录内容,最直接的方法是完全删除该目录并重新创建它。

rm -rf -- "$directory" && mkdir -p -- "$directory" || exit
Run Code Online (Sandbox Code Playgroud)

注意 的引用$directory。这是必需的,因为否则字符串 in$directory会被拆分为术语,因此如果变量的值为foo bar,代码将删除两个名称foobar。这些单词还会被扩展为文件名通配模式,这使得删除名为literal 的目录变得危险 *。我们在实际目录名称之前使用--to end 选项解析,使我们能够处理名为例如-f或 的目录--version

exit如果rm或失败,则执行以上操作mkdir。该代码自然也会重置它重新创建的目录上的所有所有权和其他元数据。

另一种方法是使用find.

find "$directory/." ! -name . -delete
Run Code Online (Sandbox Code Playgroud)

上面使用了-delete谓词find,这是非标准但普遍实现的。它删除给定目录下除目录本身之外的所有内容。在这种情况下,原始目录条目保留在原处而不是重新创建。

使用portable find,我们会这样写

find "$directory/." -depth ! -name . -exec rm -rf {} +
Run Code Online (Sandbox Code Playgroud)

cd -请注意,即使第一次失败,您的代码也会执行cd,可能会将脚本留在意外的工作目录中。您的代码也无法删除隐藏名称,并且如果通配模式扩展到太多名称,则会因“参数列表太长”而失败。如果*不匹配任何内容,它将终止使用failglob(或等效的)shell 选项集运行的脚本(请注意,如果目录预期非空,但实际上是空的,这是一件好事)。

  • 重新创建它意味着一些元数据(所有权、权限、ACL、其他扩展属性、出生时间...)将会丢失。 (3认同)