What does the ‘!’ really do when it’s added to an ex command (:wq! | :w! | :q! )?

I understand that it means force to do something.

When doing $ vim -R file I enter in read-only mode, but this works as preventive mode only

-R  Readonly mode.  The 'readonly' option will be set for all the
    files being edited.  You can still edit the buffer, but will
    be prevented from accidentally overwriting a file.  If you
    forgot that you are in View mode and did make some changes,
    you can overwrite a file by adding an exclamation mark to
    the Ex command, as in ":w!".  The 'readonly' option can be
    reset with ":set noro" (see the options chapter, |options|).
    Subsequent edits will not be done in readonly mode.  Calling
    the executable "view" has the same effect as the -R argument.
    The 'updatecount' option will be set to 10000, meaning that
    the swap file will not be updated automatically very often.

But what I can’t get yet is why it makes the instruction to skip permissions even if the file’s owner is root user, besides it also change owner & group.

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

! generally means what you’d expect from “force”, but what it means for specific command depends on the command. In the case of w!, if Vim cannot write to the file for some reason, it will try to delete and create a new one with the current buffer’s contents.

Consider the following example (observe the inode numbers):

$ touch foo
$ chmod -w foo
$ stat foo
  File: ‘foo’
  Size: 0           Blocks: 0          IO Block: 4096   regular empty file
Device: 22h/34d Inode: 10396141    Links: 1
Access: (0444/-r--r--r--)  Uid: ( 1000/ muru)   Gid: ( 1000/ muru)
Access: 2015-09-10 00:24:28.259290486 +0530
Modify: 2015-09-10 00:24:28.259290486 +0530
Change: 2015-09-10 00:24:30.771263735 +0530
 Birth: -
$ vim -c 'r!date' -c 'wq!' foo
$ stat foo                    
  File: ‘foo’
  Size: 30          Blocks: 8          IO Block: 4096   regular file
Device: 22h/34d Inode: 10396151    Links: 1
Access: (0444/-r--r--r--)  Uid: ( 1000/ muru)   Gid: ( 1000/ muru)
Access: 2015-09-10 00:24:37.727189657 +0530
Modify: 2015-09-10 00:24:37.731189614 +0530
Change: 2015-09-10 00:24:37.763189273 +0530
 Birth: -
$ cat foo
Thu Sep 10 00:24:37 IST 2015

That’s why the owner and group changes. Permissions are preserved – :h write-permissions:

                                                    write-permissions
When writing a new file the permissions are read-write.  For unix the mask is
0666 with additionally umask applied.  When writing a file that was read Vim
will preserve the permissions, but clear the s-bit.

If you want to make Vim refuse writes, see :h write-readonly:

                                                    write-readonly
When the 'cpoptions' option contains 'W', Vim will refuse to overwrite a
readonly file.  When 'W' is not present, ":w!" will overwrite a readonly file,
if the system allows it (the directory must be writable).

Note that it says “the directory must be writable” – because without a writable directory, Vim can neither delete nor create a new file.

Method 2

As stated in vim(1), -R ensures that the file will not be accidentally overwritten when the user blindly says :w, but doesn’t disable writing with :w!.

But it’s only an application, and when about to actually do something with files, the OS kernel will check permissions anyway. An experiment: I ran

strace vim /etc/hostname 2>vim.out

under a user.
Even without explicit -R it started in readonly, because it looked at permissions.
After changing the buffer

W10: Warning: Changing a readonly file

appeared.

Now :w and I got

E45: 'readonly' option is set (add ! to override)

I applied the suggestion and

"/etc/hostname" E212: Can't open file for writing

Predictably, in vim.out we see:

open("/etc/hostname", O_WRONLY|O_CREAT|O_TRUNC, 0644) = -1 EACCES (Permission denied)


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x