4

Suppose I have a sorted file, named sorted.txt, like this:

beautiful
easy
fast
functional
handy

Now, doing echo fine-grained >> sorted.txt will put "fine-grained" at the end of the file, after "handy". Is there a way to insert it in order, between "fast" and "functional", without needing to re-sort the file?

4

Although theoretically possible, there isn't a magic way to do this.

If you knew exactly what value you wanted to place it after you could use sed in-place search and replace to stick the new value in the file, but given the complexities of sorting, it basically comes down to you are going to have to sort it somewhere long the line.

echo fine-grained >> sorted.txt
sort sorted.txt > sorted.txt.new && mv sorted.txt{.new,}

Or with sponge:

{ echo fine-grained ; cat sorted.txt } | sort | sponge sorted.txt

Edit: Gilles made a good suggestion for using the -m argument for sort to potentially speed this up. From the manual:

-m, --merge
 merge already sorted files; do not sort

This would keep sort from processing all the way through the input, it only has to scan through the input files and figure out their relation to each other.

echo fine-grained | sort -m sorted.txt - | sponge sorted.txt
2
  • 3
    sort has a -m option telling it that its arguments are sorted, so echo fine-grained | sort sorted.txt - | sponge sorted.txt might be a little more efficient (you'd only notice if sorted.txt was at least about as big as your RAM). Jul 17 '11 at 10:52
  • 1
    The combination of -m & sponge seems to be the solution closest to what I originally meant. Thank you!
    – Philomath
    Jul 18 '11 at 6:05
4

You can't insert data in a file - there's nothing in the POSIX API for that. The best you can do is to seek past all the data that doesn't move, write the new line, and move all the later data down. This would be tricky and not easily done without writing your own program.

If you're happy to generate a new file, awk can do this fairly easily:

awk -v newline=fine-grained '
    !inserted && $0 > newline { print newline; inserted=1 }
    1
'

The first line of the script prints the line you want to insert only if it has not already done so and if the input line comes after the line you want to insert. It also records that the line was inserted.

The second line just prints out the input line (the expression 1 is true, and the default action is to print the input line, so we do not need to say { print }.

0
0

A direct answer to your question is NO, you'll need to run some type of sort somewhere along the line.

0

You'll have to put it through some type of sort, its' just a matter of when. But what I suspect you're looking for is a one-shot deal. Your method is up to you, and there are various ways that may be faster.

This gets the job done, but feel free to play around with other ways.

echo "$(echo fine-grained | cat - sorted.txt | sort)" > sorted.txt

Deconstructed, starting with the inner subshell to avoid truncating the file before reading it, concatenate the echoed input with the diskfile. Echoing it quoted preserves line breaks. Then sort it.

Or the compacted, with Giles' suggestion of sort -m (and avoiding UUOC).

echo "$(echo fine-grained | sort -m - sorted.txt)" > sorted.txt
6
  • 1
    I tried this sequence using bash and all I got was the "fine-grained" line in the sorted.txt. What is happening of course is that sorted.txt is being cleared by the output redirection of the sort and thus the cat will only generate that from the echo.
    – mdpc
    Jul 17 '11 at 5:15
  • 1
    @bahamat: In spite of having mentioned the issue, your use of a command replacement subshell does nothing to keep the file from being clobbered.
    – Caleb
    Jul 17 '11 at 7:13
  • @mdpc @caleb Sorry, sort needs to be inside the subshell. Corrected. If you can, please remove the -1.
    – bahamat
    Jul 17 '11 at 14:16
  • @bahamat I removed my -1 because this works now, but no upvote because putting redirects on the end of a command chain is a good way to accidentally clobber your data, using a subshell as an anti-clobber solution isn't something I would teach.
    – Caleb
    Jul 17 '11 at 20:07
  • Short & elegant, not bad at all.
    – Philomath
    Jul 17 '11 at 20:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.