And touch allows you to do chmod +x afterwards, before editing, which would make sense if you are writing a #!/bin/bash shell script.
– Aaron McDaidJun 3 '16 at 10:02

12

Alternatively, you can just do :w first thing after starting vi though. (and :chmod +x % if you want to make it executable)
– Stéphane ChazelasJun 3 '16 at 10:36

26

touch may fail where vi's :w! would have succeeded though (for instance if file exists but you're not its owner and don't have write access to it, while you have write access to the current directory). Conversely, touch may succeed but vi's :w or :w! may fail if you're owner of the file, but don't have write access to it nor to the current directory (you'd be able to work around it with :!chmod +w % (some vi implementations like vim can do that automatically upon :w!)).
– Stéphane ChazelasJun 3 '16 at 10:51

Vim / vi very clearly state if you open a file that you do not have permission to write to: "foo" [readonly]. And again when entering insert mode: Warning: Changing a readonly file.
– DevSolarJun 6 '16 at 9:44

good point, so it's essentially a good way to discover if people is using/editing the same file and warn them at the same time. I see a clear benefit of that in a multi-tenant environment!
– FawixJun 3 '16 at 13:12

@Fawix then you should update this answer Aswell
– KiwyJun 3 '16 at 18:16

It is worth noting that touch is used to update file timestamps. If you use touch on a file that exists, it will then update the files timestamp to the current date and time. If the file does not exist, it creates an empty file with the current date and time as the timestamp.

vi, on the other hand, does not create a new file unless you write to it.

For example, if I typed vi test.txt, typed some notes, then typed :q!; test.txt would not exist.

Consider a multi-user system (perhaps you're on an network-mounted filesystem shared by many systems each with many users). Running touch will ensure you have the file (and that you can write to it) and even updates the timestamp. Another user wanting to create such a file will see that you own it. If it already exists and another user wants to delete or replace it, they'll see that it was recently modified and perhaps think twice.

There is no benefit to touching first; vi will create the file if it does not exist.

The accepted answer says it checks whether you can write there before wasting time in an editor. True, but now you'll be wasting time typing touch every time. Not being able to write somewhere is fairly exceptional compared to how often it will just work (as long as you remember sudo for files outside your home directory or /tmp, or are logged in as root).

Just open up the editor and do what you want, then try to save the file. If it doesn't work, even with :w!, save it elsewhere (:w ~/asdf) and fix the problem. Once it's fixed, you can copy the file contents from the temporary file to the original: cat ~/asdf > /mnt/example.txt && rm ~/asdf. The reason we use cat instead of mv or cp is to use the destination's permissions and other attributes.

Moreover, for some more advanced command line usage, you could background vi with Ctrl+Z while you fix the problem (or use :suspend, or :sus), and finally fg it again to run the write command.

There are some security issues here: (1) If the file /mnt/example.txt is not supposed to be world-readable, but your umask is set to something permissive like 22, then /tmp/asdfwill be world-readable. If there are other people on the system, they may be able to read the temporary copy of the file. (2) The file /mnt/example.txt is probably not supposed to be world-writable, but, if there are malicious people on the system, they may be able to read the temporary copy of the file and replace it with a modified version before you move/copy it back to the right location. … (Cont’d)
– G-Man Says 'Reinstate Monica'Jun 5 '16 at 12:29

3

(Cont’d) … (Setting the sticky bit on /tmp may prevent this.) (3) The command mv /tmp/asdf /mnt/example.txt will totally destroy the current /mnt/example.txt and replace it with /tmp/asdf. You want to replace the content of /mnt/example.txt with the content of /tmp/asdf. By using mv, you set up /mnt/example.txt to have the same attributes as /tmp/asdf — probably owned by you and world-readable. It might be better to cp /tmp/asdf /mnt/example.txt or even cat /tmp/asdf > /mnt/example.txt. … P.S. (4) You can suspend vi by typing :suspend (or :sus, for short).
– G-Man Says 'Reinstate Monica'Jun 5 '16 at 12:29

@G-Man Those are some good points. I'm not particularly scared of someone stealing a file during the 5 minutes it's in /tmp, but there is no excuse for not writing to ~/ instead. I also hadn't thought of that it would replace the attributes. I'll edit my post, thanks :)
– LucJun 5 '16 at 15:45

vi is a visual text editor (vi = visual) It's visual compared to "ed" anyway, which just lets you see and change one line of text at a time.

The touch command updates the timestamp on an existing file, or creates a new file if the file didn't already exist. It's good for testing things that are highly dependent on timestamps.

Now if your file is a text file, or doesn't yet exist, opening it with vi, then issuing the command :wq to vi, would have the same result as touching that file. That's the only way the two commands are similar at all.

Specifically for use with vi, there is no need to create the file before you edit it: vi can be used to create and save a new file. However, there are calling contexts where the file needs to exist. For example, on my system (OS X) I can launch an appropriate GUI editor (determined by file type) like this:

open foo.txt

This would open foo.txt in TextEdit, or in emacs, or whatever I specified as my editor of choice for text files, and detach the process so that I get my prompt back immediately. (open bar.py might open it in IDLE, the python editor; etc.) Or I can explicitly request emacs:

open -a emacs foo.txt

But open requires the file to exist already, otherwise it raises an error. So I had to define emacs to be the following shell function, which allows me to write emacs foo to launch the emacs GUI even if foo does not exist.