sponge

sponge 英文意思是 海绵 ,有一个著名的动画 海绵宝宝 SpongeBob :

../../_images/SpongeBob.jpg

著名动画 「海绵宝宝 SpongeBob」

sponge 工具命令包含在 moreutils 软件包中,通常在 Ubuntu Linux 需要单独安装:

Ubuntu Linux 中通过安装 moreutils 获得 sponge 工具
apt install moreutils

为什么叫 sponge (海绵)呢? 原因是这个工具提供了类似 soak up (吸干) 功能:

使用 sponge

sponge 命令没有任何命令选项,唯一接受的参数是一个文件名: 例如,你可以输入 sponge newfile.txt

回车以后,你会看到终端等待你输入,你可以输入任意行内容,直到你按下 ctrl+d ( EOF ) 表示结束输入。

接下来,你就会在当前目录看到一个文件 newfile.txt ,内容就是你刚才在屏幕终端输入的内容。

那么,你会问,这有什么用处,我不能用 shell重定向 来实现同样的功能么?

sponge 命令 vs shell重定向

sponge 命令的真正威力是结合管道 pipe 来使用

  • 以下是一个简单 spongeshell重定向 案例:

spongeshell重定向 案例
echo "Put this text in a file" | sponge file1.txt

echo "Put this text in a file" > file2.txt

粗看似乎没有区别…

如果你经常编写shell,就会知道,当一个重定向( redirect )打开一个文件写入,然后又从 stream 流读取内容到重定向管道,就会破坏文件:

grep 一个文件的案例
$ cat cities.txt 
# Cities in Pennsylvania
Philadelphia
Pittsburgh
Harrisburg
# Cities in New Jersey
Camden
Trenton
Newark

$ grep -v '^#' cities.txt
Philadelphia
Pittsburgh
Harrisburg
Camden
Trenton
Newark

可以看到 grep -v '^#' 可以过滤出文件中没有 # 注释的内容

但是,如果把上面 grep 输出到标准输出(终端)的内容再重定向到被过滤文件的自身,就会看到文件内容完全被清空了(并不是像你想象的那样去除#注释,保留正式内容):

grep 一个文件又重定向回这个文件自身会清空文件
$ grep -v '^#' cities.txt > cities.txt
grep: cities.txt: input file is also the output
$ cat cities.txt
$

所以,很多时候对上述情况,我们会采用一个中间临时文件来存储 grep 过滤中间结果,处理外后再复制回源文件:

grep 内容到临时文件,再将处理后文件复制回源文件
$ grep -v '^#' cities.txt > cities.tmp
$ mv cities.tmp cities.txt
$ cat cities.txt
Philadelphia
Pittsburgh
Harrisburg
Camden
Trenton
Newark

很麻烦,不是么?

现在有请 sponge 出场:

使用管道结合 sponge 可以重定向回源文件而且不破坏内容
$ grep -v '^#' cities.txt | sponge cities.txt
$ cat cities.txt
Philadelphia
Pittsburgh
Harrisburg
Camden
Trenton
Newark

参考