34
> brew install moreutils ==> Downloading https://homebrew.bintray.com/bottles/moreutils-0.55.yosemite.bottle.tar.gz ######################################################################## 100.0% ==> Pouring moreutils0.55.yosemite.bottle.tar.gz 🍺 /usr/local/Cellar/moreutils/0.55: 67 files, 740K 

sponge reads standard input and writes it out to the specified file. Unlike a shell redirect, sponge soaks up all its input before writing the output file. This allows constructing pipelines that read from and write to the same file.

I don't understand. Please give me some useful examples.

What does soaks up mean?

3

3 Answers 3

48

Assume that you have a file named input, you want to remove all line start with # in input. You can get all lines don't start with # using:

grep -v '^#' input 

But how do you make changes to input? With standard POSIX toolchest, you need to use a temporary file, some thing like:

grep -v '^#' input >/tmp/input.tmp mv /tmp/input.tmp ./input 

With shell redirection:

grep -v '^#' input >input 

will truncate input before you reading from it.

With sponge, you can:

grep -v '^#' input | sponge input 
11
  • 5
    You actually can read and write a file at the same time safely as long as the bytes are only being transformed, using the <> operator. Commented Jun 6, 2015 at 9:14
  • @ChrisDown: Yes, I mean without making it corroupt Commented Jun 6, 2015 at 9:19
  • 1
    @ChrisDown: Let me remove that sentence to avoid confusing. I actually mean when using <>file, you open file for reading and writing but you actually don't write anything to file. Commented Jun 7, 2015 at 7:12
  • Did you try it? :-) <> has no problem writing to a file, try it for yourself: printf foobar >q; printf bar 1<>q results in barbar. Commented Jun 7, 2015 at 7:46
  • 8
    I think the point that @ChrisDown is trying to make is that <> doesn't truncate a file, but merely replaces its existing bytes with the new output. If the new output is too short, you'll have leftover garbage at the end of the file. But if the new output is long enough, there's no risk. Commented Aug 2, 2018 at 13:56
20

The moreutils home page itself documents a typical use case:

sed "s/root/toor/" /etc/passwd | grep -v joey | sponge /etc/passwd 

Here, /etc/passwd is both being written to and read to, and is being modified. Without sponging up stdin before writing, /etc/passwd might be corrupted (as the file changed during reading).

1
  • 4
    And that would be a good example on the moreutils page, if it had explained the way you did :-) Commented Jan 24, 2020 at 22:55
1

The easiest example of sponge I've ever read:

$ cat file1 I You Me We Us 

To sort it, you can simply

$ sort file1 > file1_sorted 

However, with sponge, you can read from and write to at the same file.

$ sort file1 | sponge file1 

without requiring the temporary file file1_sorted. This is because sponge first read from STDIN, and then write it out to STDOUT, in separate steps, thus avoiding corrupting the file as it is changed during the reading.

2
  • 1
    Using sort as an example is a bit awkward, as you would rather use sort -o file1 file1 to sort the file in place (i.e., sort already has this "built-in", so to speak). Commented Mar 12, 2024 at 9:41
  • @Kusalananda It really doesn't matter. Commented Jan 16 at 19:29

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.