Add command for working with file in-place
It's common to transform a file in place. For example, to change each line to title case:
use str
cat file | each $str:title~ | to-lines > file.new
mv file.new
It would be nice if a process-in-place command supports processing a file in place without needing the boilerplate. It takes
process-in-place file $str:title~
Were you envisioning this being a builtin written in Go? Because it seems to me it should be possible to implement this in Elvish. But rather than bundling it, ala pkg/eval/bundled/epm.elv.go, this is the sort of thing that is a good candidate for a site wide directory of Elvish modules as discussed in #1004. Perhaps in a "util" or "file-util" module.
If this were a shell builtin, I would expect the modified file to inherit all the metadata of the original: Owner, group, filemode, ACLs, extended attributes …, you name it. In particular, if the file contents is sensitive, I want any temporary file to be at least as protected as the original, so that no data can leak. All of that seems a very thorny problem to get right in a portable way.
It's perhaps easiest on a Mac with APFS: Your example could be written as
use str
use unix
unix:umask=177 cp -c file file.bak # clone copy, practically free
cat file.bak | each $str:title~ | to-lines > file
rm file.bak # (optional)
You still face the problem of how to recover in case an error happens. Also, this has different semantics if the original file has multiple hard links. But that is a bit beside my point, which is that different strategies may be called for on different platforms and for different use cases.
I'm wondering if @xiaq based this idea on Perl's perl -pi -e pattern. I used to frequently use that pattern but haven't in the recent past. I've never paid any attention to how well that mechanism preserved the characteristics of the original file. A quick, and trivial, test shows that it does not honor the file being read-only. In other words, if you create a file and do chmod 444 z; perl -pi -e s/x/X/' z perl will happily modify the file. Yes, it preserved the 0444 permission but it (arguably) should not have modified the file in the first place since it did not have write permission. Which shows how difficult it is to correctly to implement something like this feature.
Having said the above.... Providing this feature as a builtin makes it easier to do the correct thing most of the time. Requiring the user to know how to check and copy file permissions, ownership (e.g., the primary group), ACLs, etc., is not realistic. On the other hand it's dangerous for Elvish to provide this as a builtin since it is impossible to guarantee that it will correctly honor and preserve all file attributes. Including things like ACLs or other extended attributes.
A year later I am a strong thumbs down on this proposal. The adverse security outcomes posed by implementing this proposal far outweigh its casual use value.
Maybe instead just provide a command overwrite-content which would by definition just overwrite the content with another content. This way all metainformation of the file/dir should stay preserved etc. Actually overwrite-content would essentially be just >> known from POSIX shells but starting from the beginning of the file.
@dumblob How is that different from redirection using >?
@hanche I'd expect from overwrite-content to be power-outage safe (unlike >) by not using truncate (and maybe also to somehow smartly deal with other processes currently reading/writing to the same file). But otherwise it'd be the same as >.