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

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

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

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

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

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

更新:

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

答案1

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

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

rm -rf -- "$directory" && mkdir -p -- "$directory" || exit

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

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

另一种方法是使用find.

find "$directory/." ! -name . -delete

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

使用portable find,我们会这样写

find "$directory/." -depth ! -name . -exec rm -rf {} +

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

答案2

找到最终不需要的替代模式rm -rf或者安全的地方也是一个好主意。

一个例子可能是广泛使用mktemp存储到函数局部变量的路径,这样所有内容都可以自行清理。如果您没有将未知文件的整个树摄取到您的进程中,您可能永远不需要它。

如果您正在摄取树,您可能可以确保您的工作路径上有一个固定的前缀,这样/即使变量意外为零,您也不会擦除。

答案3

针对空变量的最简单和最常见的保护rm -rf是确保变量不为空。

if [ -n "$directory" ]; then
   rm -rf "$directory"
fi

当您附加到基本路径时,这是一项重要的检查,以确保您最终不会仅传递基本路径,从而删除远远超出预期的内容。考虑这个例子:

rm -rf "/home/user/$Dir"

如果变量$Dir为空,则命令将为rm -rf /home/user/

如果您更了解要删除的内容,您还可以检查以确保路径是文件-f或目录-d

man test有关测试表达式的大多数信息,请参阅 参考资料。

引用可以防止路径名中出现空格将其分成 2 个参数。

相关内容