如何复制一个立即被删除的文件

Eri*_*kli 7 command-line scripts

我有一个脚本,该脚本创建一个转储/path/of/directory并立即删除它。我想在删除该转储之前复制它。

我试过;

dump=$(ls -a | grep -E "^[0-9]+$")
cp $dump fulldump
Run Code Online (Sandbox Code Playgroud)

但我只拿到了一半的剧本,没有完整的剧本。

llo*_*rus 20

您可以使用 chattr 来防止文件删除(同时允许创建和修改文件)以及其他方便的权限

对于目录:

sudo chattr -R +a /TEMP/
Run Code Online (Sandbox Code Playgroud)

或者如果只是(现有)文件:

sudo chattr +a /TEMP/youCantDeleteMe.txt
Run Code Online (Sandbox Code Playgroud)

要恢复权限,请-a使用+a

$ mkdir Documents/TEMP && cd $_
$ echo can edit > youCantDeleteMe.txt 

$ sudo chattr -R +a ../TEMP/

$ echo after plusA on file>> youCantDeleteMe.txt 
$ cat youCantDeleteMe.txt 
can edit
after plusA on file

$ sudo rm youCantDeleteMe.txt 
rm: cannot remove 'youCantDeleteMe.txt': Operation not permitted

$ ls -lA
-rw-rw-r-- 1 v v   25 Sep  5 05:59 youCantDeleteMe.txt
$ echo . > youCantDeleteMe.txt 
bash: youCantDeleteMe.txt: Operation not permitted

$ touch somebody
$ ls -lA
-rw-rw-r-- 1 v v  0 Sep  5 06:04 somebody
-rw-rw-r-- 1 v v 25 Sep  5 05:59 youCantDeleteMe.txt

$ sudo rm somebody 
rm: cannot remove 'somebody': Operation not permitted

$ sudo chattr +a ./undel.txt
chattr: No such file or directory while trying to stat ./undel.txt
Run Code Online (Sandbox Code Playgroud)

并稍后删除该文件

$ sudo chattr -R -a ../TEMP/
$ ls -lA
drwxrwxr-x 2 v v 4096 Sep  5 06:17 .
drwxr-xr-x 7 v v 4096 Sep  5 05:57 ..
-rw-rw-r-- 1 v v    0 Sep  5 06:04 somebody
-rw-rw-r-- 1 v v   25 Sep  5 05:59 youCantDeleteMe.txt

$ rm -rf ./*
$ ls -la
drwxrwxr-x 2 v v 4096 Sep  5 06:17 .
drwxr-xr-x 7 v v 4096 Sep  5 05:57 ..
 
Run Code Online (Sandbox Code Playgroud)


use*_*733 19

恭喜,看来您已经创建了竞争条件

  • 两个进程竞相对同一文件执行操作。

  • 一般来说,竞争条件被认为是一个错误,其原因正是您遇到的——结果是不可预测的。

有多种方法可以修复竞争条件(信号量、锁定文件、延迟等),其中一些可能涉及相当大量的编码。

但是,在您的具体情况下,您询问了script。令人高兴的是,您可以编辑脚本。最简单的解决方案是编辑脚本以将转储放置在您的首选位置。

  • “管道文件”将是*命名管道*(搜索该术语;那里有很棒的教程)。这是上面问题中需要包含的重要信息,它完全改变了可能的答案:访问数据可能就像“cat < $dump”一样简单 (15认同)
  • 添加@user535733的评论:它还将获取文件内容的机会(不会从脚本中窃取该数据!)更改为零:它不是一个文件,它是一个命名管道。它可以像文件一样读取和写入,但有一个关键的区别:数据永远不会写入磁盘,所有内容只能读取一次。因此,如果 OP 设法从该命名管道读取(部分)数据,则该数据将丢失给脚本中的管道使用者! (12认同)
  • 那么你就无法修复竞争条件。向该软件的开发人员提交错误。或者继续尝试重复复制文件——每次您都会得到不同数量的转储。在某些时候,你可能会得到全部的东西。 (4认同)
  • @Erikli 脚本意味着可读的纯文本,而不是二进制可执行文件。如果这是真的,您可以复制它,更改副本,然后更改系统以使用您的副本而不是原始版本吗?这可能就像重命名原始版本(作为备份 - 不要删除它)并在同一位置为您的版本提供相同的名称一样简单。(现在相同的代码运行*您的*版本,即使它是硬编码的) (4认同)

Nat*_*dge 15

strace实用程序通常用于显示进程进行的系统调用,但它也可以拦截它们。

尝试:

strace -f -e inject=unlink,unlinkat:retval=0 /the/script script-args...
Run Code Online (Sandbox Code Playgroud)

然后,每次进程或其子进程调用unlinkunlinkat系统调用(这是删除文件的正常方法)时,strace都会拦截它并使其返回 0,表示成功,但实际上不执行任何操作。

将会有大量输出跟踪所有系统调用。您可以添加-e trace=unlink,unlinkat以仅显示这些调用,或-o logfile将整个输出发送到文件(可能/dev/null)。确保这些参数位于/the/script命令行之前。

请注意,这将阻止脚本删除任何文件;希望没关系。有一个-P选项strace应该将跟踪限制为访问给定文件的调用,但我无法让它在简单的测试中正常工作。

其他变体也是可能的:例如,您可以使unlink/unlinkat系统调用失败并显示错误代码,或者让它们向进程发送 SIGSTOP ,以便您可以在继续之前进行查看。有关其所有功能的详细信息,请参阅 strace 手册页。


小智 6

根据转储打开和写入的速度,您也许能够在写入时创建指向它的硬链接。此硬链接将确保当使用其原始名称删除文件时,数据空间不会被释放。例如:

your-script &
ln /path/of/directory/dumpfile /some/other/path/on/the/same/filesystem
wait   #  wait until your-script exits
do-something-with /some/other/path/on/the/same/filesystem
Run Code Online (Sandbox Code Playgroud)