How to prevent saving file in vim - vim

I'm customizing vim (vimdiff) as a testing tool for diffing certain files, and would like to disable saving the files completely - however, I haven't been able to stop :w! .. I've tried starting vim/vimdiff with -R option, and I have also tried setting cpoptions to contain W, which means:
cpo-W
W Don't overwrite a readonly file. When omitted, ":w!"
overwrites a readonly file, if possible.
..but vim seems not to care about this:
echo yo > foo
vim -R foo
:set cpoptions=aABceFsW
:set cpoptions?
cpoptions=aABceFsW
:w
E45: 'readonly' option is set (add ! to override)
:w!
"foo" 1L, 3C written
..bug, or did I misunderstand it?

You just told Vim that it should run in "readonly mode". The file itself is not readonly. If you chmod -w foo, then Vim would not allow to write the file on :w! while W is present in cpoptions.
You could try to start Vim with -M:
vim -M foo
This disallows any changes to the file and prevents writing the file. See :help -M.
Another solution might be:
vim -m foo
This opens the file and you can edit it (you get the warning W10: Warning: Changing a readonly file), but you are not able to write it. The option write is reset (to nowrite) and prevents writing to any file. So this is global.
If you finally decide, that you need to write it anyway, you have to set the option with the command :set write. As said, this is global, so you are than able to write any file.

It's much better to work on the file permissions, or to use the -M option as stated by #user7369280, but the funny thing is you can also launch vi with certain options that will prevent you to use the classic w or wq commands for example:
vi my_file -c 'cabbrev w <esc>' -c 'cabbrev wq <esc>'
It basically disables the commands w and wq with redefining them with the command escape (which doesn't do much)

Related

Cygwin terminal input disappearing after quitting vim

Using Cygwin, I tried creating and editing a file in Vim:
touch test | vim
This is obviously a mistake; something like vim "$(touch test)" has a better chance of actually working. Nevertheless, this command throws the error:
Vim: Warning: Input is not from a terminal.
And after this, Vim opens and I exit the program with :q. Any subsequent commands I enter into the terminal are hidden from view until I restart Cygwin.
Why is this?
You don't understand what does a pipe | do in shell.
Pipe will take the pervious command's stdout as stdin to next command, in a subshell.
Your touch foo doesn't generate any output, what do you expect to happen? same for vim "$(touch test)".
If you want to create a file and open it in vim in one shot, you can try:
touch foo && vim foo
If you want to edit it with vim anyway, actually, you can simply just:
vim foo
then save the buffer after your editing.

need to write a script to change file format from dos to unix

I have to make a script using vim which opens a file, set the fileformat=unix, and then save the file and exit. Could you please help? Thanks
First, check out whether you have a dos2unix or dos2ux command; it already does this for you.
With Vim, this should do the job:
$ vim -c "wq ++ff=unix" filename
This one in-lines the fileformat change with the :w command; of course, you can also do this separately via -c "set ff=unix".
Notes
You can also do this via a variety of tools, e.g. sed, perl, ...; Vim is a quite heavyweight alternative.
This still starts up a full, interactive Vim instance. Have a look at this answer which additional command-line arguments can turn Vim into batch mode.

Why doesn't "history | vim" work?

I want to use the Vim to see the result of history (not in the shell). I think history | vim will work (use the result of history as the input of vim), but it returns with:
$history | vim
Vim: Warning: Input is not from a terminal
Vim: Error reading input, exiting...
Vim: Finished.
Can anybody explain this?
By piping into vim, you are changing the standard input stream. Because vim is an interactive program, it requires the standard input to be the console.
If you want to view in vim, you should tell it you are reading the file from stdin (by supplying the argument -):
history | vim -
Alternatively, you could just use more or less:
history | more
history | less
These latter two are preferable. If you pipe into vim, it will see your "file" as having modifications, and so you can't quit with a straight :q command. Instead you have to force quit by :q!, which is a bit clunky.
On the other hand, you can exit more or less just by typing q. Have a look at the man-page for these two programs. You'll use them a lot.
As recommended by Russell Silva in the comments, you can open vim in read-only mode when you read from stdin. Just supply the -R argument. Then you can quit normally without needing the override:
history | vim -R -
Apart of vim -, you may try bash command substitution like:
vim <(history)
See also:
How to write whole buffer to standard output from the command line? at Vim SE
How to edit files non-interactively (e.g. in pipeline)? at Vim SE
This happend to me trying to send it to background console (&)
One script used:
...
vi "$file" &
...
# change to just:
vi "$file"
removing &, problem went away.

adding a shell script to a configuration file

I'm pretty new to shell scripting and linux in general. Basically, I need to change the configuration file for logging out so that when a user logs out, a certain shell script is run.
Now, I've located the logout configuration file and opened it with vi using this command
$ vi ~/.bash_logout
At this point, I'm experiencing some very weird behavior. When I try to type a character, the cursor jumps around seemingly erratically. What could this be due to? I'm running the latest version of ubuntu.
And once I get that figured out, what's the command to run a .sh file from within this configuration file?
If you're having trouble with vi, try using nano instead. nano .bash_logout
If you do need to use vi for some reason, "i" will put the editor into insert mode, and ESC will take it out of insert mode when you're done. ":wq" will write and quit the editor.
To run a command, just put it in the .bash_logout file as you would type it on the commandline.
Some other useful commands:
a insert after selected character
o insert at next line
O insert at previous line
r replace a single character
R replace mode
:q! quit without saving
:w save
:wq save and quit
To get familiar with Vi and its brother Vim ("VI improved") I recommend the book "A Byte of Vim", you can read it online or download for free at http://www.swaroopch.com/notes/Vim
You can permanently change your editor option. To find out what your current one is, type this:
export | grep -i edit
To change it on Ubuntu:
sudo update-alternatives –config editor
On any other BASH prompt, just do this:
export EDITOR="nano"
Replace 'nano' with 'vi', 'emacs', or any other preferred editor. You can also add this to your .bashrc by typing the following:
echo 'EDITOR="nano"' >> ~/.bashrc

How do you get sudo access for a file inside the vi text editor? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about a specific programming problem, a software algorithm, or software tools primarily used by programmers. If you believe the question would be on-topic on another Stack Exchange site, you can leave a comment to explain where the question may be able to be answered.
Closed 3 years ago.
Improve this question
Often while editing config files, I'll open one with vi and then when I go to save it realize that I didn't type
sudo vi filename
Is there any way to give vi sudo privileges to save the file? I seem to recall seeing something about this while looking up some stuff about vi a while ago, but now I can't find it.
% is replaced with the current file name, thus you can use:
:w !sudo tee %
(vim will detect that the file has been changed and ask whether you want to it to be reloaded. Say yes by choosing [L] rather than OK.)
As a shortcut, you can define your own command. Put the following in your .vimrc:
command W w !sudo tee % >/dev/null
With the above you can type :W<Enter> to save the file. Since I wrote this, I have found a nicer way (in my opinion) to do this:
cmap w!! w !sudo tee >/dev/null %
This way you can type :w!! and it will be expanded to the full command line, leaving the cursor at the end, so you can replace the % with a file name of your own, if you like.
In general, you can't change the effective user id of the vi process, but you can do this:
:w !sudo tee myfile
Common Caveats
The most common method of getting around the read-only file problem is to open a pipe to current file as the super-user using an implementation of sudo tee. However, all of the most popular solutions that I have found around the Internet have a combination of a several potential caveats:
The entire file gets written to the terminal, as well as the file. This can be slow for large files, especially over slow network connections.
The file loses its modes and similar attributes.
File paths with unusual characters or spaces might not be handled correctly.
Solutions
To get around all of these issues, you can use the following command:
" On POSIX (Linux/Mac/BSD):
:silent execute 'write !sudo tee ' . shellescape(#%, 1) . ' >/dev/null'
" Depending on the implementation, you might need this on Windows:
:silent execute 'write !sudo tee ' . shellescape(#%, 1) . ' >NUL'
These can be shortened, respectfully:
:sil exec 'w !sudo tee ' . shellescape(#%, 1) . ' >/dev/null'
:sil exec 'w !sudo tee ' . shellescape(#%, 1) . ' >NUL'
Explanation
: begins the command; you will need to type this character in normal mode to start entering a command. It should be omitted in scripts.
sil[ent] suppresses output from the command. In this case, we want to stop the Press any key to continue-like prompt that appears after running the :! command.
exec[ute] executes a string as a command. We can't just run :write because it won't process the necessary function call.
! represents the :! command: the only command that :write accepts. Normally, :write accepts a file path to which to write. :! on its own runs a command in a shell (for example, using bash -c). With :write, it will run the command in the shell, and then write the entire file to stdin.
sudo should be obvious, since that's why you're here. Run the command as the super-user. There's plenty of information around the 'net about how that works.
tee pipes stdin to the given file. :write will write to stdin, then the super-user tee will receive the file contents and write the file. It won't create a new file--just overwrite the contents--so file modes and attributes will be preserved.
shellescape() escapes special characters in the given file path as appropriate for the current shell. With just one parameter, it would typically just enclose the path in quotes as necessary. Since we're sending to a full shell command line, we'll want to pass a non-zero value as the second argument to enable backslash-escaping of other special characters that might otherwise trip up the shell.
#% reads the contents of the % register, which contains the current buffer's file name. It's not necessarily an absolute path, so ensure that you haven't changed the current directory. In some solutions, you will see the commercial-at symbol omitted. Depending on the location, % is a valid expression, and has the same effect as reading the % register. Nested inside another expression the shortcut is generally disallowed, however: such as in this case.
>NUL and >/dev/null redirect stdout to the platform's null device. Even though we've silenced the command, we don't want all of the overhead associated with piping stdin back to vim--best to dump it as early as possible. NUL is the null device on DOS, MS-DOS, and Windows, not a valid file. As of Windows 8 redirections to NUL don't result in a file named NUL being written. Try creating a file on your desktop named NUL, with or without a file extension: you will be unable to do so. (There are several other device names in Windows that might be worth getting to know.)
~/.vimrc
Platform-Dependent
Of course, you still don't want to memorize those and type them out each time. It's much easier to map the appropriate command to a simpler user command. To do this on POSIX, you could add the following line to your ~/.vimrc file, creating it if it doesn't already exist:
command W silent execute 'write !sudo tee ' . shellescape(#%, 1) . ' >/dev/null'
This will allow you to type the :W (case-sensitive) command to write the current file with super-user permissions--much easier.
Platform-Independent
I use a platform-independent ~/.vimrc file that synchronizes across computers, so I added multi-platform functionality to mine. Here's a ~/.vimrc with only the relevant settings:
#!vim
" Use za (not a command; the keys) in normal mode to toggle a fold.
" META_COMMENT Modeline Definition: {{{1
" vim: ts=4 sw=4 sr sts=4 fdm=marker ff=unix fenc=utf-8
" ts: Actual tab character stops.
" sw: Indentation commands shift by this much.
" sr: Round existing indentation when using shift commands.
" sts: Virtual tab stops while using tab key.
" fdm: Folds are manually defined in file syntax.
" ff: Line endings should always be <NL> (line feed #09).
" fenc: Should always be UTF-8; #! must be first bytes, so no BOM.
" General Commands: User Ex commands. {{{1
command W call WriteAsSuperUser(#%) " Write file as super-user.
" Helper Functions: Used by user Ex commands. {{{1
function GetNullDevice() " Gets the path to the null device. {{{2
if filewritable('/dev/null')
return '/dev/null'
else
return 'NUL'
endif
endfunction
function WriteAsSuperUser(file) " Write buffer to a:file as the super user (on POSIX, root). {{{2
exec '%write !sudo tee ' . shellescape(a:file, 1) . ' >' . GetNullDevice()
endfunction
" }}}1
" EOF
If you're using Vim, there is a script available named sudo.vim. If you find that you've opened a file that you need root access to read, type:e sudo:%Vim replaces the % with the name of the current file, and sudo: instructs the sudo.vim script to take over for reading and writing.
Ryan's advice is generally good, however, if following step 3, don't move the temporary file; it'll have the wrong ownership and permissions. Instead, sudoedit the correct file and read in the contents (using :r or the like) of the temporary file.
If following step 2, use :w! to force the file to be written.
When you go into insert mode on a file you need sudo access to edit, you get a status message saying
-- INSERT -- W10: Warning: Changing a readonly file
If I miss that, generally I do
:w ~/edited_blah.tmp
:q
..then..
sudo "cat edited_blah.tmp > /etc/blah"
..or..
sudo mv edited_blah.tmp /etc/blah
There's probably a less roundabout way to do it, but it works.
A quick Google seems to give this advice:
Don't try to edit if it's read-only.
You might be able to change the permissions on the file. (Whether or not it will let you save is up to experimentation.)
If you still edited anyway, save to a temporary file and then move it.
http://ubuntuforums.org/showthread.php?t=782136
Here's another one that has appeared since this question was answered, a plugin called SudoEdit which provides SudoRead and SudoWrite functions, which will by default try to use sudo first and su if that fails: http://www.vim.org/scripts/script.php?script_id=2709
I have this in my ~/.bashrc:
alias svim='sudo vim'
Now whenever I need to edit a config file I just open it with svim.
A quick hack you can consider is doing a chmod on the file you're editing, save with vim, and then chmod back to what the file was originally.
ls -l test.file (to see the permissions of the file)
chmod 777 test.file
[This is where you save in vim]
chmod xxx test.file (restore the permissions you found in the first step)
Of course I don't recommend this approach in a system where you're worried about security, as for a few seconds anyone can read/change the file without you realizing.

Resources