在运行shell脚本时,如何防止覆盖或截断文件?

如果应用程序正在运行其使用的共享库之一被写入或截断,则应用程序将崩溃。 移动文件或使用'rm'批量删除文件不会导致崩溃,因为操作系统(Solaris在这种情况下,但我认为这在Linux和其他* nix上也是如此)足够聪明,不会删除与该文件,而任何进程打开。

我有一个执行共享库安装shell脚本。 有时,可能会用它来重新安装已经安装的共享库的版本,而无需首先卸载。 因为应用程序可能正在使用已经安装的共享库,所以重要的是脚本足够聪明,可以将文件打包或移动(例如,当我们知道没有应用程序时,cron可以清空的“已删除”文件夹将会运行),然后再安装新的程序,以免被覆盖或截断。

不幸的是,最近一个应用程序在安装后崩溃。 巧合? 很难说。 这里真正的解决scheme是切换到一个更老的安装方法,而不是一个旧的巨大的shell脚本,但它会很高兴有一些额外的保护,直到开关制成。 有没有什么方法来包装一个shell脚本,以防止覆盖或截断文件(理想情况下大声失败),但仍然允许他们移动或rm'd?

标准的UNIX文件权限不会执行这个技巧,因为你无法区分移动/删除和覆盖/截断。 别名可以工作,但我不知道什么样的命令需要别名。 我想像truss / strace之类的东西,除非在每个动作之前检查filter是否真正做到这一点。 我不需要一个完美的解决scheme,甚至可以对付有意识的恶意脚本。

我到目前为止的想法是:

  • 别名cp到GNU cp(因为我在Solaris上不是默认的)并使用–remove-destination选项。
  • 别名安装到GNU安装并使用–backup选项。 将现有文件移动到备份文件名称可能非常聪明,而不是复制,从而保留了inode。
  • 在〜/ .bashrc中设置“noclobber”,以便I / Oredirect不会覆盖文件

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

在安装软件时,特别是在安装现有软件时,正常的安全操作模式是(或者我的意思是'应该'):

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

如果在复制东西时出现问题,则不会损坏现有的安装。 这当然假设你有足够的磁盘空间 – 但是磁盘很便宜。

如果你正在编写你自己的安装程序,你可以做类似的事情。 如果你正在使用其他人的安装程序,你将很难处理他们的怪癖。 最终,你需要向供应商投诉。 但是请注意,如果您尝试摆弄标准命令,这些更改可能会回来并咬你。

我的第一个想法是在〜/ .bashrc中build议'设置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 } 

我认为rsync可能是这个工具。 您可能需要结合干运行或逐项更改来满足您的确切要求。 --ignore-existing开关也可能是有趣的。

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