Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

A friend of mine points out that if you do:

perl -pi.bak -e 's/foo/bar/' somefile

when "somefile" is actually a symlink, perl does just what the docs say it will do:

It does this by renaming the input file, opening the output file by the original name, and selecting that output file as the default for print() statements. The extension, if supplied, is used to modify the name of the old file to make a backup copy [...]

Which results in a new symlink "somefile.bak" pointing to the unchanged real file, and a new, changed regular file "somefile" with the changes.

In many cases, following the symlink would be the desired behavior (even if it leaves the correct location of the .bak file ambiguous). Is there a simple way to do this other than testing for symlinks in a wrapper and handling the case appropriately?

(sed does the same thing, for what that's worth.)

share|improve this question
Call vim or emacs (I think both do follow symlinks)? Seriously, I fear the answer is to reimplement -p -i in your script. – Gilles Mar 15 '11 at 21:20
Sed does not in fact do the same thing, at least not since version 4.2.1, released in June of 2009. You must include the --follow-symlinks option for the edit to edit the linked-to file rather than clobbering the symlink; I assume this was done to avoid breakage of existing scripts which may depend on the old behavior. – Garrett Sep 7 '14 at 16:49
up vote 5 down vote accepted

I wonder whether the small sponge general-purpose utility ("soak up standard input and write to a file") from moreutils will be helpful in this case and whether it will follow the symlink.

The author describes sponge like this:

It addresses the problem of editing files in-place with Unix tools, namely that if you just redirect output to the file you're trying to edit then the redirection takes effect (clobbering the contents of the file) before the first command in the pipeline gets round to reading from the file. Switches like sed -i and perl -i work around this, but not every command you might want to use in a pipeline has such an option, and you can't use that approach with multiple-command pipelines anyway.

I normally use sponge a bit like this:

sed '...' file | grep '...' | sponge file
share|improve this answer
Hey cool, that works. I suspect Gilles's comment above is the "real" answer, but since he didn't make it as an answer, and since I learned a new utility, I'll take this one. :) – mattdm Mar 16 '11 at 0:26
But have you tested sponge for such a usage in practice? As for me: not yet. Could you please leave a comment stating whether it behaved in a test the way wanted here? Oh, I see the comment. Thanks for the confirmation! – imz -- Ivan Zakharyaschev Mar 16 '11 at 0:28
— yes, I tried it before replying. When file in your example above is a symlink, the link is left alone and the real file changed. – mattdm Mar 16 '11 at 0:38
@mattdm: Yes, thanks for the confirmation! (I noticed your words "that works" a bit later than I wrote my comment.) – imz -- Ivan Zakharyaschev Mar 16 '11 at 0:42

If you know for a fact that somefile is a symlink, you can explicitly supply the full path to file with the following:

perl -pi.bak -e 's/foo/bar/' $(readlink somefile)

That way, the original symlink stays intact since the replacement is now done directly with the original file.

share|improve this answer

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

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