What does the "inplace" modification of a file e.g. via sed -i or perl -i mean?
My question is about how this inplace modification is done. Is the file copied the modification is done in the copy and then replace the original? Or is the original file somehow being modified in place?

  • Have a look at backreference.org/2011/01/29/in-place-editing-of-files for a detailed explanation of this topic. – scy Jul 23 '14 at 8:31
  • For that matter, how is it done with ex or vi? – Wildcard Feb 4 '16 at 8:10
  • @Wildcard - each of those has a whole system in place. ex maintains a mailfile (like, dead.mail or something in ~you, and another somewhere near to your mail spooler, usually). check the specs - each of them has state defined to great lengths... ex has its own binary format in most cases (look at your -rescue file) and this is used to prezero separate temporary buffer files (possibly as many as six). so these copy out blocks of input to edit buffers ans sync writes into offsets per changes :!written? – mikeserv Jan 20 at 9:16

sed creates a temporary file, writes the output into that file, and then renames the temporary file over the top of the original.

You can watch what happens using strace:

$ strace -e trace=file sed -i -e '' a
execve("/usr/bin/sed", ["sed", "-i", "-e", "", "a"], [/* 34 vars */]) = 0
open("a", O_RDONLY)                     = 3
open("./sedxvhRY8", O_RDWR|O_CREAT|O_EXCL, 0600) = 4
rename("./sedxvhRY8", "a")              = 0
+++ exited with 0 +++

This logs all the file operations sed makes: it creates a new file (safely with O_CREAT|O_EXCL), writes the data into it, and then moves it back over the top of my original file a.

sed -i accepts a suffix to use for a backup, and in that case it moves the original out of the way first (rather than renaming over the top). That argument is mandatory in most BSD seds. In this case, there's a brief time when there's no file by the right name in the directory at all.

perl in recent versions opens the input file, then deletes it and creates a new file with the same name:

open("a", O_RDONLY)               = 3
unlink("a")                       = 0
open("a", O_WRONLY|O_CREAT|O_EXCL, 0600) = 4

When you delete (unlink) a file you already have open you retain access to it for as long as you keep the handle around, so it can keep reading the data out of the deleted file. In this way perl writes directly into the output file, rather than into a temporary file: no additional file is created, but if you read the file during the process you'll get partial content, unlike with sed's approach. There's also a brief time when there's no file with the right name, which is at the start of the process rather than the end (as in sed -i .bak).

Both sed and perl will:

  • Replace a symbolic link with an ordinary file.
  • Break hard links.
  • Preserve group ownership if possible.
  • Create the file with your default group (or the group of the parent directory if that directory has the setgid bit) if it was owned by a group you're not in and you're not root.
  • Preserve file ownership if you're root.
  • Preserve basic permissions.
  • Preserve setuid and setgrp bits, if the resulting group is the same as the group it started in.
  • Preserve the sticky bit.
  • Not preserve xattrs.

sed will:

  • Preserve ACLs (On Linux; I don't know about others).

perl will:

  • Not preserve ACLs.

The above is true on Linux with GNU sed and Mac OS X with its (FreeBSD-derived) sed.


In additional to @Homer's answer, from perldoc perlrun:

specifies that files processed by the "<>" construct are to be edited in-place. 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, following these rules:

If no extension is supplied, no backup is made and the current file is overwritten.

If the extension doesn't contain a *, then it is appended to the end of the current filename as a suffix. If the extension does contain one or more * characters, then each * is replaced with the current filename.

And remember that, no soft link or hard link is preserved:

Note that because -i renames or deletes the original file before creating a new file of the same name, UNIX-style soft and hard links will not be preserved.

Finally, the -i switch does not impede execution when no files are given on the command line. In this case, no backup is made (the original file cannot, of course, be determined) and processing proceeds from STDIN to STDOUT as might be expected.

This also explains why you must use -i with -p option, or use a explicit print statement if you want to edit inplace with perl:

# Opps, file will be truncated, becomes empty
$ perl -i.bak -ne 's/123/qwe/' file

# Right way
$ perl -i.bak -ne 's/123/qwe/;print' file

# Or
$ perl -i.bak -pe 's/123/qwe/' file

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.