在Linux文件系统中,文件实际上是指向索引节点的链接,该索引节点包含文件的属性,例如所有权,权限,数据块的地址等。当使用rm命令删除文件时,将删除指向其索引节点的链接,但不指向索引节点的链接。其他进程仍可以将其打开。完成操作后,所有链接都将被删除,一个inode及其指向的数据块可用于写入。

现在,如果某个进程仍打开了文件,那么数据就在某个地方,即使根据列出的目录,该文件似乎已经消失了。Linux进程伪文件系统/ proc目录在这里生效。系统上的每个进程都有一个带有其名称的目录,其中包含许多内容,例如:文件描述符,它是一个子目录,包含指向该进程已打开的所有文件的链接。即使文件已从文件系统中删除,该数据的副本也将在那里:

/ proc /进程id / fd / file_descriptor

现在找到它,您需要获取打开了文件的进程的ID,以及文件描述符。这些是通过lsof获得的,这意味着“列出打开的文件”。

一旦从lsof获得了该信息,就可以从/ proc中复制数据并获得(实际上)丢失的内容。

您可以使用以下示例对此进行测试

首先,创建一个文本文件,您可以将其删除然后再带回:

$ man lsof | col -b > test_file

然后看一下您刚刚创建的文件的内容:

$ less test_file

您应该看到lsof的大型手册页的纯文本版本看着您,礼貌些。

现在按Ctrl-Z暂停less。返回一个shell提示符,确保您的文件仍然存在:

$ ls -l test_file

-rw-r--r--. 1 root root 124467 Oct 14 13:42 test_file

# stat test_file

  File: ‘test_file’

  Size: 124467          Blocks: 248        IO Block: 4096   regular file

Device: fd00h/64768d    Inode: 2149553030  Links: 1

Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)

Context: unconfined_u:object_r:admin_home_t:s0

Access: 2019-10-14 13:42:13.633798195 +0800

Modify: 2019-10-14 13:42:08.749021536 +0800

Change: 2019-10-14 13:42:08.749021536 +0800

 Birth: -

$ rm test_file

$ stat test_file

stat: cannot stat ‘test_file’: No such file or directory

在这里,我们绝不能允许仍然使用该文件的进程退出,因为一旦发生这种情况,该文件将真正消失并且您的麻烦将会加剧。现在,如果这是您正在播放的视频或声音文件,那么当您意识到已删除文件时,要做的第一件事就是立即暂停应用程序的播放,或者冻结该过程,以便它最终不会停止播放文件并退出。

现在将文件带回来。首先,看看lsof必须说些什么:

$ lsof | grep test_file

less      2615                root    4r      REG              253,0    124467 2149553030 /root/test_file (deleted)

第一列为您提供与该进程关联的命令的名称,第二列为该进程的ID,第四列中的数字为文件描述符(“ r”表示它是常规文件)。现在您知道进程2615仍然打开了文件,并且知道了文件描述符4。这就是将其从/ proc中复制出来所需要的一切。

我们可能会认为,将-a标志与cp一起使用是正确的做法,因为我们正在还原文件,但是实际上不要这样做很重要。否则,您将不复制文件中包含的文字数据,而只是将一个现在断开的符号链接复制到该文件,因为该文件曾经在其原始目录中列出:

$ ls -l /proc/2615/fd/4

lr-x------. 1 root root 64 Oct 14 13:45 /proc/2615/fd/4 -> /root/test_file (deleted)

$ cp /proc/2615/fd/4  test_file

最后,确认您做得不错:

$ ls -l test_file

-rw-r--r--. 1 root root 124467 Oct 14 13:48 test_file

$ man lsof | col -b> test_file1

$ cmp test_file test_file1

文件没有差异,这表明还原成功。