118

Am I blind or is there no option like --in-place for sort?

In order to save results to the input file, sed uses -i (--in-place).

Redirecting the output of sort to the input file

sort < f > f

results in making it empty. If there is no --in-place option - maybe there is some trick how to do this in handy way?

(The only thing that cames to my mind:

sort < f > /tmp/f$$ ; cat /tmp/f$$ > f ; rm /tmp/f$$

Moving is not right choice, cause file permissions might be changed. That's why I overwrite with the contents of the temp file which I then remove.)

6
  • 1
    There is also insitu, allowing any commands to be used in-place.
    – sr_
    Commented Jan 22, 2012 at 10:19
  • @sr_, that's an interesting command, but it doesn't work with any command, only ones that write no faster than they read (otherwise it'll clobber the input file before the command reads it). There's no guarantee that it'll work with sort.
    – cjm
    Commented Jan 22, 2012 at 11:09
  • @cjm, I'm really not sure, but isn't this supposed to handle that case?
    – sr_
    Commented Jan 22, 2012 at 13:39
  • @sr_, I think you're right. I read the description instead of looking at the source. Although for really big files, it might run out of memory for the buffer and crash (it doesn't look like it checks for a NULL return from malloc).
    – cjm
    Commented Jan 22, 2012 at 14:02
  • @cjm: Oh yes, indeed.
    – sr_
    Commented Jan 22, 2012 at 14:19

4 Answers 4

162

sort has the -o (or --output) option that takes a filename as argument.  The program writes the data to a temporary file, then overwrites the original input file after the sort is complete (which can happen only after all the input data have been read).  (This is essentially the same thing as what sed -i does.)

From GNU sort info page:

    -o OUTPUT-FILE
    --output=OUTPUT-FILE
      Write output to OUTPUT-FILE instead of standard output. Normally, sort reads all input before opening OUTPUT-FILE, so you can safely sort a file in place by using commands like sort -o F F and cat F | sort -o F. However, sort with --merge (-m) can open the output file before reading all input, so a command like cat F | sort -m -o F - G is not safe, as sort might start writing F before cat is done reading it.

      On newer systems, -o cannot appear after an input file if POSIXLY_CORRECT is set, e.g., sort F -o F. Portable scripts should specify -o OUTPUT-FILE before any input files.

and from The Open Group Base Specifications Issue 7:

    -o output
      Specify the name of an output file to be used instead of the standard output. This file can be the same as one of the input files.
There have been reports that sort might discard (i.e., destroy) some or all of your data if you are out of disk space or out of disk quota, or the system crashes while sort is writing the output file, or some other error occurs.

In short, to sort a file in place, the following may be used:

sort -o filename filename
1
  • I just used sort -o file file and realized I forgot LC_ALL=C (to speed sort) up, so hit ^C. OK, take tw--wait that finished quickly?? Apparently interrupting an in-place sort may make it truncate the file.
    – i336_
    Commented Oct 4, 2022 at 4:01
16

You can use the sponge function, that first soaks the stdin and then writes it to a file, like:

sort < f | sponge f

The downside of sponge is that it will store the output temporary in memory, which can be problematic for large files. Otherwise you have to write it to a file first and then overwrite the original file.

As however is pointed out by other answers, in place modifications are in general not a good idea, since in the middle of a process (for instance the sponge one), the machine might crash and then you can lose both the original and new file. You better first write it to a different file and then use an atomic mv (move) instruction.

2
  • 2
    Another downside: sponge is not a standard Unix tool. It must be installed. Commented Aug 27, 2020 at 1:04
  • I've had bad experiences with sponge. If the source command fails (non-zero exit code), sponge still overwrites the file. This has never been what I wanted (though I concur the "correct" behavior is not a given).
    – olejorgenb
    Commented Jul 30, 2022 at 8:20
8

It's dangerous to overwrite the input file with the output file, because if the program or the system crashes while the file is being written, you've lost both.

A few programs (mostly GNU versions) have an in-place option (e.g. -i on perl and GNU sed; -o on GNU sort). They work by putting the data in a temporary file and then moving it into place.

For programs that have no such option, Colin Watson's sponge utility (included in Joey Hess's moreutils) does the job atomically for any program (examples: Can I make cut change a file in place?; How can I make iconv replace the input file with the converted output?). However, beware that do_stuff | sponge myfile always overwrites myfile, possibly with empty or incorrect output, even if do_stuff fails: sponge can't detect whether the command that's piped into it succeeded. So it's handy to type, but it's unsafe, compared to using a temporary file.

Only in those rare cases where you can't recreate the original file with the same permissions do I recommend overwriting the file in place. In this case, you'd better save the original input somewhere. And then you can simply process the copy of the input and send it into the original file.

cp -p f ~/f.backup
sort <~/f.backup >|f
rm ~/f.backup # optional
5
  • 2
    sort -o is not GNU specific, and is especially designed to orverride the file in place. sort cannot start writing its output before it has read its inputs fully (uses memory or temporary files to store data), so it comes quite naturally that it should be able to override its input. Commented Nov 8, 2015 at 15:47
  • And actually, it's one case where GNU sort is not POSIX as sort -mo file1 file1 file2 is not guaranteed to work while traditional sorts know how to work around that (alread in Unix V7 in the 70s). Commented Nov 8, 2015 at 15:56
  • @JoelCross Odd, sort -o works for me with coreutils 8.25 and the property is documented in the manual (noting that it's only the case when sorting, not when merging). If you can reproduce this, send a bug report (indicating the exact command line, the exact input file(s), what system you're running it on and how you obtained the binary). Commented Aug 24, 2016 at 10:07
  • > It's dangerous to overwrite the input file with the output file, because if the program or the system crashes while the file is being written, you've lost both. GNU sort -o will destroy both if it, or your system, crashes, or if your disk is full.
    – Habbie
    Commented Apr 18, 2021 at 15:47
  • 1
    I've had bad experiences with sponge. If the source command fails (non-zero exit code), sponge still overwrites the file. This has never been what I wanted (though I concur that the "correct" behavior is not a given).
    – olejorgenb
    Commented Jul 30, 2022 at 8:18
5

Use -o or try the vim-way:

$ ex -s +'%!sort' -cxa file.txt

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .