是否可以在开头截断文件(就地,相同的索引节点)?

9 shell tail files truncate

可以删除 a 的尾随字节,file而无需写入新文件 ( > newfile) 并将其移回 ( mv newfile file)。这是通过以下方式完成的truncate

truncate -s -1 file
Run Code Online (Sandbox Code Playgroud)

可以删除前导字节,但通过移动它(这会改变 inode)(对于某些版本的 tail):

tail -c +1 file > newfile ; mv newfile file
Run Code Online (Sandbox Code Playgroud)

那么:如何在不移动文件的情况下做到这一点?
理想情况下,就像截断一样,即使对于非常大的文件也只需要更改几个字节。

注意:sed -i将更改文件索引节点,因此,即使它可能有用,也不是这个问题的答案(IMO)。

Sté*_*las 6

ksh93

tail -c+2 < file 1<>; file
Run Code Online (Sandbox Code Playgroud)

(其中<>;是标准<>运算符的 ksh93 特定变体,如果重定向的命令成功,它最终会截断文件)。

将删除第一个字节(通过将文件的其余部分写入自身并在末尾截断)。

同样可以用以下方法完成sh

{
  tail -c+2 < file &&
    perl -e 'truncate STDOUT, tell STDOUT'
} 1<> file
Run Code Online (Sandbox Code Playgroud)

请注意,它会解稀疏稀疏文件(尽管之后您仍然可以重新挖洞fallocate -d)。

出现读/写错误时,tail可能会退出,使文件部分被覆盖(因此,例如,abcdefgh可能最终会bcddefgh导致重写后失败bcd)。您可以调整上述内容,以便它在出现错误时报告写入偏移量,以便您知道如何恢复数据。仍然有ksh93

unset -v offset
{ tail -c+2 < file || false >#((offset=CUR)); } 1<>; file
Run Code Online (Sandbox Code Playgroud)

之后$offset设置 if,它包含已成功写入的数据量。

在 Linux(自 3.15 起)和 ext4 或 xfs 文件系统上,可以使用系统调用或实用程序折叠文件系统块大小的倍数的范围或字节大小和偏移量。fallocate()fallocate

例如

fallocate -c -l 8192 file
Run Code Online (Sandbox Code Playgroud)

将删除文件的前 8192 字节(假设 FS 的块大小是 8192 的除数),而不必重写文件的其余部分。但如果您想删除不是 FS 块大小倍数的部分,那么这是没有用的。

  • @Paul_Pedant,“&lt;&gt;;”运算符是 ksh93 扩展。它类似于 Bourne/标准的 `&lt;&gt;` 运算符,但如果命令成功,则会在末尾截断。您可能遇到了[该错误](https://github.com/att/ast/issues/9),或者您可能使用 t+ (2010) 之前的 ksh93 版本 (2认同)

Pau*_*ant 1

取决于您所说的“非常大的文件”是什么意思。你的极限是什么?

您可以将整个内容读入内存(作为 awk 字符串),并将子字符串写回原始文件。在某个阶段,awk 会同时包含原始数据和子字符串,但对于 0.5 GB 来说,这是一个可行的解决方案。awk 在我的笔记本电脑上每秒处理大约 80 MB。

在 C 中很容易,因为您只需移动写入的起始指针即可。