8

I have shell (php) script that gets in touch with target file this way:

  • inspects whether file and directory are writable with php 's is_writable() (I don't think that this is problem)
  • does in-place file edit with sed command:

grep -q "$search" "$passwd_file" && { sed -i "s|$search|$replace|" "$passwd_file"; printf "Password changed!\n"; } || printf "Password not changed!\n"

As a result I get (everything else correct but) file which was myuser:www-data to be myuser:myuser .

Does sed changes file group ownership as it seems, and how do I avoid it, if possible?

16

There is a little problem with sed's inplace editing mode -i. sed creates a temporary file in the same directory called sedy08qMA, where y08qMA is a randomly generated string. That file is filled with the modified contents of the original file. After the operation, sed removes the original file and renames the temporary file with the original filename. So it's not a true inplace edit. It creates a new file with permissions of the calling user and a new inode number. That behavior is mostly not bad, but for instance, hard links get broken.

However, if you want true inplace editing, you should use ed. It reads commands from the stdin and edits the file directly, without a temporary file (it's done over ed's memory buffer). A common practise is to use printf to generate the command list:

printf "%s\n" '1,$s/search/replace/g' wq | ed -s file

The printf command produces output as follows:

1,$s/search/replace/g
wq

Those two lines are ed commands. The first one searches for the string search and replaces it with replace. The second one writes (w) the changes to the file and quits (q). -s suppresses diagnostic output.

8

The -i parameter of sed works by creating a temp file during operation, then overwrite the actual file with the temp file in the end. That's the most likely the cause of the problem, since when creating the temp file ownership defaults to myuser:myuser

You can set the setgid bit on the parent directory(only if the parent directory is owned by group www-data), so that files created under this directory inherit the same group.
to do that:

chmod g+s parent-dir-of-your-file  

I think this is a very typical use of the setgid bit.

  • @cuonglm I just did a strace on sed -i, found the following line in the trace, does it mean it created the temp file in current dir? open("./sedKyG9Ei", O_RDWR|O_CREAT|O_EXCL, 0600) = 4 – David Dai Apr 15 '16 at 8:50
  • @DavidDai: Yes, my mis-memory. – cuonglm Apr 15 '16 at 9:07
2

The use of ed instead of sed seems rather superfluous for this, given you have to pipe in an additional input. The distro I'm working on right now (CentOS 5.10) has the -c option for sed that utilizes 'copying' of the temp file rather than simply renaming it when used with the -i option. I've tested it and it worked perfectly, preserving the original owner and group when doing an inline edit. It does NOT preserve the modification time.

e.g., sed -ci -e '3,5d' file.txt

  • -c uses copy instead of rename (i.e., preserves ownership/group)
  • -i inline editing
  • -e script/expression to be executed

Not sure how widespread this option is for sed across other distros. Solaris 10 didn't have it, but Solaris doesn't have a lot of things I want.

  • Sounds pretty handy. Not in Ubuntu 14.04 though, FWIW. :-( – John Rix Sep 10 '18 at 9:54

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.