我经常想做这样的事情:
cat file | command > file
(这显然不起作用)。我看到的唯一解决方案是sponge
,即
cat file | command | sponge file
不幸的是,sponge
我无法使用(我也无法安装它或任何其他软件包)。
有没有更标准的快速方法来做到这一点,而不必每次都将其分解为多个命令(管道到临时文件,管道返回原始文件,删除临时文件)?例如,我尝试过tee
,它似乎有效,但它是一致/安全的解决方案吗?
我经常想做这样的事情:
cat file | command > file
(这显然不起作用)。我看到的唯一解决方案是sponge
,即
cat file | command | sponge file
不幸的是,sponge
我无法使用(我也无法安装它或任何其他软件包)。
有没有更标准的快速方法来做到这一点,而不必每次都将其分解为多个命令(管道到临时文件,管道返回原始文件,删除临时文件)?例如,我尝试过tee
,它似乎有效,但它是一致/安全的解决方案吗?
一个shell函数替换
sponge
:这个
mysponge
shell 函数将标准输入上的所有可用数据传递到一个临时文件。当所有数据都被重定向到临时文件时,收集的数据被复制到函数参数命名的文件中。如果不将数据附加到文件中(即
-a
不使用),并且如果给定的输出文件名引用现有的常规文件,如果它不存在,则使用mv
(如果文件是现有的常规文件,首先尝试使用 GNU 将文件模式转移到临时文件chmod
)。如果输出不是常规文件(命名管道、标准输出等),则数据以cat
.如果命令行上没有给出文件,则收集的数据将发送到标准输出。
最后,临时文件被删除。
函数中的每一步都依赖于上一步的成功完成。如果一个命令失败(它可能包含重要数据),则不会尝试删除临时文件。
如果命名的文件不存在,那么它将使用用户的默认权限等创建,并将来自标准输入的数据写入其中。
该
mktemp
实用程序不是标准的,但通常可用。上述函数模仿了 Debian 软件包手册中描述的行为。
sponge
moreutils
使用
tee
代替sponge
将不是一个可行的选择。你说你已经尝试过了,它似乎对你有用。它可能有效,也可能无效。它依赖于管道中命令的启动时间(它们几乎是同时启动的),以及输入数据文件的大小。以下是一个示例,显示了 using
tee
不起作用的情况。原始文件是 200000 字节,但在管道之后,它被截断为 32 KiB(这很可能对应于我系统上的一些缓冲区大小)。
有这个简短的 bash 脚本,需要 Perl
https://github.com/ildar-shaimordanov/perl-utils#sponge
第二个脚本应该是 moreutils 中版本的直接替换
还有一个版本是独立的 perl 脚本。
接下来我们使用函数