Kev*_*all 4 bash sed perl files
我已经读过:有没有办法就地修改文件?
我很好奇是否有办法使用不会创建临时文件的命令来修改文件。假设我创建了一个目录
mkdir read_only
,然后在 read_only 中创建了一些文件。当我愉快地完成创建文件时,我运行chmod 555 read_only. 现在是否可以在不使用临时文件的情况下修改任何文件?具体来说,我想要一个可以从 bash 脚本完成的解决方案。我不想知道是否有可能;我也在寻求解决方案。到目前为止,我使用 bash/unix 命令管理的所有想法都会创建临时文件。
编辑:我相信我的问题不是Can a file be edit with 'write' permission on it 但不是在其父目录上的重复?出于以下原因:
Gil*_*il' 10
您需要目录的写权限才能创建或删除其中的文件,但不需要写入其中的文件。大多数 shell 命令,当给定一个输出文件时,只需打开该文件进行写入,并替换以前在文件中的数据。所述>重定向操作截断现有的文件(即,删除现有的文件的内容,从而产生具有零长度的文件),并开始写入到它。所述>>重定向操作者使数据被附加到文件的末尾。
写入文件受到低级接口提供的可能性的限制。您可以就地覆盖文件中的字节,附加到文件末尾,并将文件截断为选定的长度。您不能在向前移动后续字节时插入字节(如foobar? fooNEWSTUFFbar),也不能在向后移动后续字节时删除字节(如foobar? for),除非通过读取数据以移动数据并将其写入新位置来模拟这些操作。
就地编辑文件的问题在于,如果出现问题(程序错误、磁盘已满、断电……),很难确保文件内容保持一致。这就是为什么稳健的文件处理通常涉及使用新数据写入临时文件,然后将该临时文件移动到位。
就地编辑文件的另一个限制是涉及读取和写入的复杂操作不是原子的。仅当某些其他任务可能希望在您修改的同时读取文件时,才会出现此问题。例如,如果你改变foobar以fooNEWSTUFFbar通过读取最后3个字节(bar),然后写入新的数据(foo?fooNEWSTUFF),最后追加老尾(fooNEWSTUFF?fooNEWSTUFFbar),并发读者可能看到fooNEWSTUFF,或者文件的,只有一部分甚至是其他的局部状态写入的数据。同样,首先写入临时文件解决了这个问题,因为将临时文件移动到位是一个原子操作。
如果您不关心这些限制,那么您可以就地修改文件。附加数据很容易 ( >>),大多数其他转换都涉及更多。一个常见的陷阱是
somefilter <somefile >somefile
Run Code Online (Sandbox Code Playgroud)
不适somefilter用于文件内容:>操作员在somefilter开始读取之前截断输出文件。
Joey Hess 的 moreutils包含一个实用程序sponge,它可以解决这个问题。不是将输出重定向到somefile,而是将其通过管道传输到sponge,后者会读取其所有输入,然后使用读取的输入覆盖现有文件。请注意,如果过滤器失败,仍有可能得到部分数据。
somefilter <somefile | sponge somefile
Run Code Online (Sandbox Code Playgroud)
如果你没有sponge,解决这个问题的便携简单方法是首先将数据读入内存:
content=$(cat somefile; echo a)
content=${content%a}
Run Code Online (Sandbox Code Playgroud)
该echo a位是在该文件的末尾保留换行符-命令替换总是剥掉后换行。然后,您可以将内容传递给命令:
printf %s "$content" | somefilter >somefile
Run Code Online (Sandbox Code Playgroud)
这将用过滤器的输出替换文件的内容。如果命令因任何原因失败,文件的原始内容将丢失,文件包含命令在失败之前写入的任何数据。
请注意,此方法不适用于二进制文件,因为大多数 shell 不支持空字节。
另一种就地修改文件的方法是使用ed编辑器,它与 非常相似sed,但将文件加载到内存中并就地保存,这与 sed 的逐行操作相反。
仅使用标准 shell 工具来处理文件而不将其加载到内存中并且不创建临时文件是比较棘手的,但它可以做到。Shell 重定向和大多数文本处理实用程序只允许您附加到文件或从头开始覆盖它。您可以使用dd conv=notrunc seek=…覆盖文件中某个偏移处的数据,而不会影响未被覆盖的部分;请参阅有没有办法就地修改文件?举个例子。