Due to the ubiquity of the Vi editor, vi followed by a file path or name is at the fingertips of many UNIX users. However, sometimes this command can lead to issues due to the current user’s control over the file.
For brevity, we’ll use vi (Vi) when referencing both the Vi and Vim editors.
We tested the code in this tutorial on Debian 11 (Bullseye) with GNU Bash 5.1.4. It should work in most POSIX-compliant environments.
2. Vi and File Permissions
To begin with, let’s see how Vi handles situations in which our actions are in conflict with the current file permissions.
2.1. Other User Without Permissions
Naturally, even the almighty Vi doesn’t enable us to even see a file we’re not allowed to:
$ ls -l /etc/shadow -rw-r----- 1 root shadow 1010 Nov 11 01:01 /etc/shadow $ whoami baeldung $ vi /etc/shadow "/etc/shadow" [Permission Denied][...]
First, we use ls to check the permissions of /etc/shadow. Next, we get the current user via whoami. At this point, we verify that our shell user can’t read, write, or execute /etc/shadow.
As expected, the attempt to open /etc/shadow with vi results in an error.
2.2. Other User With Read-Only Permissions
Let’s try another file, which our user can only read:
$ ls -l /file -rwx---r-- 1 root root 9 Nov 22 06:56 /file $ cat /file Content. $ vi /file [...] "/file" [readonly]
In this case, we get a warning instead of an error about the fact that /file is read-only. Let’s attempt to enter Insert mode by pressing i:
-- INSERT -- W10: Warning: Changing a readonly file
After another warning, we can continue by pressing Return. If we make any changes and attempt to save via :w[rite], we see an error:
E45: 'readonly" option is set (add ! to override)
While the error prevents us from saving, pressing Return and following its advice to use :write! or :w!, we finally hit a wall:
"/file" "/file" E212: Can't open file for writing
At this point, Vi throws an error. The editor attempts to reopen the file with write permissions enabled, but without success, since we don’t have enough control:
- can’t write the file
- can’t change the file permissions
So, what happens when we own the file and are able to do the latter?
2.3. Owning User or Group With Read-Only Permissions
Now, we take ownership of /file, reset its permissions to read-only for the owner, and retry to open and modify it with Vi:
$ ls -l /file -r-------- 1 baeldung baeldung 9 Nov 22 06:56 /file $ cat /file Content. $ vi /file [...] "/file" [readonly]
Of course, we see the original warning. Yet, following the steps above to modify and forcefully save the file via :w!, we’re successful:
"/file" 1L, 10B written
Since our current user owns the file, Vi can use that to enable saving the changes without permanently modifying the permissions.
Furthermore, we can run a shell command from within the editor to make the change permanent:
:!chmod u+w %
In this case, we use chmod to add (+) the [w]rite permission over the current file path (% percent register) for the owning [u]ser.
2.4. Vi Read-Only
Further, the Vi editor also provides a readonly or ro setting, which, once enabled, prevents accidental writes. In such cases, we can just turn readonly off:
Now, we should be able to write as usual, barring other complications.
What other options do we have when attempting to write to a read-only file without owning the file?
3. Override File Permissions with Vi
Even without owning a given file, we still have ways to save it with Vi. Let’s see how.
3.1. User With sudo Privileges
If we want to write to a file, instead of owning or having permissions over it, we can instead elevate our privileges. In fact, we can even do that for only one save operation:
:w !sudo tee %
Here, we use the ! exclamation point operator, not the ! exclamation point command, as confirmed by the space character just after the write command. Moreover, by running tee with sudo privileges for our file path in the % percent register, we redirect the current buffer to that file.
To ease the process, we can create a new command with :cno[remap]:
cnoremap ww! execute 'silent! write !sudo tee % >/dev/null' edit!
This mapping assigns ww! to two actions, separated by a pipe:
- Silently :exe[cute] the write command with sudo tee from above
- Perform a forced :e[dit] to refresh the contents
Now, by simply typing :ww! and pressing Return, we can save without write permissions as long as we have sudo privileges.
3.2. User Without Permissions
Without any permissions and the means to acquire them, we still have an option: save the changes to a temporary location.
To do so, we can simply supply another file to our write command:
In this case, the provided file location is the current user’s home directory to ensure we can write to it.
Alternatively, we can use diff with its –ed to just keep a summary of the edits:
:0,$!diff --ed % -
First, we select everything from the 0 first to the $ last line. After that, we pass it to diff, creating an ed script from the current buffer content as the standard input argument (–) and the read-only file as % percent. Finally, we replace the buffer contents with the ed script contents, allowing us to save a new file with just the changes and apply it in another context at a later point.
In this article, we discussed different ways to preserve our changes and save a file opened without write permissions in Vi.
In conclusion, while Vi doesn’t circumvent the security mechanisms of Linux, it provides a way to work around them when the conditions permit.