运行 shell 脚本时,如何保护它不被覆盖或截断文件?

运行 shell 脚本时,如何保护它不被覆盖或截断文件?

如果应用程序运行时,其使用的共享库之一被写入或截断,则应用程序将崩溃。使用“rm”移动文件或将其全部删除不会导致崩溃,因为操作系统(本例中为 Solaris,但我认为 Linux 和其他 *nix 也是如此)足够智能,不会在任何进程打开文件时删除与文件关联的 inode。

我有一个用于安装共享库的 shell 脚本。有时,它可能用于重新安装已安装的共享库版本,而无需先卸载。由于应用程序可能正在使用已安装的共享库,因此重要的是脚本足够智能,可以在安装新文件之前 rm 文件或将它们移开(例如,移到“已删除”文件夹中,当我们知道没有应用程序运行时,cron 可以清空该文件夹),这样它们就不会被覆盖或截断。

不幸的是,最近一个应用程序在安装后就崩溃了。巧合吗?很难说。真正的解决方案是切换到比旧的巨型 shell 脚本更强大的安装方法,但在切换之前最好有一些额外的保护。有没有办法包装 shell 脚本以防止覆盖或截断文件(理想情况下会大声失败),但仍允许移动或 rm 它们?

标准 UNIX 文件权限无法解决问题,因为您无法区分移动/删除和覆盖/截断。别名可以起作用,但我不确定哪些命令需要全部使用别名。我想象类似 truss/strace 的东西,只不过在每次操作之前,它会根据过滤器检查是否真的要执行该操作。我不需要一个即使针对故意恶意的脚本也能起作用的完美解决方案。

我目前的想法:

  • 将 cp 别名为 GNU cp(由于我在 Solaris 上,所以不是默认设置)并使用 --remove-destination 选项。
  • 别名安装到 GNU 安装并使用 --backup 选项。它可能足够聪明,将现有文件移动到备份文件名而不是制作副本,从而保留 inode。
  • 在 ~/.bashrc 中“set noclobber”,这样 I/O 重定向就不会覆盖文件

答案1

使用install实用程序——这就是它的用途。

答案2

安装软件时,尤其是在现有软件上安装时,正常的安全操作模式是(或者我的意思是“应该是”?):

  • 在目标目录中以临时名称 t1 创建新文件
  • 设置权限(所有者、组、模式、ACL 等)
  • 将旧文件移动到临时名称 t2
  • 将新文件 t1 移至永久名称
  • 最后删除t2

如果在复制内容时出现问题,则不会损坏现有安装。当然,这假设您有足够的备用磁盘空间 - 但磁盘很便宜。

如果您正在编写自己的安装程序,则可以执行类似操作。如果您正在使用其他人的安装程序,您将很难处理他们的怪癖。最终,您需要向供应商投诉。但请注意,如果您尝试摆弄标准命令,这些更改可能会给您带来麻烦。

答案3

我的第一个想法是建议在 ~/.bashrc 中“set noclobber”。

再想想:Solaris 有 lsof、fuser 或 fstat 吗?这些可以检查另一个进程是否打开了文件。

你也可以尝试这样的方法:

safecp() { 
  source=$1
  dest=$2
  dest_dir=$(dirname dest)
  [ -d $dest_dir] || mkdir $dest_dir/temp && mv $dest $dest_dir/temp && cp $source $temp 
}

答案4

需要考虑的另一件事是,跨文件系统边界使用“cp”会将数据写入当前 inode,而同一文件系统内的 cp 将取消与旧文件的链接并链接到新文件。

相关内容