I want to write a Bash shell script that does the following:
Opens a file using Vim;
Writes something into the file;
Saves the file and exits.
echo 'About to open a file'
vim file.txt # I need to use vim application to open a file
# Now write something into file.txt
...
# Then close the file.
...
echo 'Done'
Is that possible? I found something called Vimscript, but not sure how to use it.
Or something like a here document can be used for this?
Update: I need to verify that Vim is working fine over our file
system. So I need to write script that invokes Vim, executes some
command, and closes it. My requirements do not fit into doing stuffs
like echo 'something' > file.txt. I got to open the file using Vim.
ex is the commandline version for vi, and much easier to use in scripts.
ex $yourfile <<EOEX
:%s/$string_to_replace/$string_to_replace_it_with/g
:x
EOEX
Vim has several options:
-c => pass ex commands. Example: vim myfile.txt -c 'wq' to force the last line of a file to be newline terminated (unless binary is set in some way by a script)
-s => play a scriptout that was recorded with -W. For example, if your file contains ZZ, then vim myfile.txt -s the_file_containing_ZZ will do the same as previously.
Also note that, invoked as ex, vim will start in ex mode ; you can try ex my_file.txt <<< wq
You asked how to write "something" into a text file via vim and no answer has necessarily covered that yet.
To insert text:
ex $yourfile <<EOEX
:i
my text to insert
.
:x
EOEX
:i enters insert mode. All following lines are inserted text until . is seen appearing by itself on its own line.
Here is how to search and insert as well. You can do something such as:
ex $yourfile <<EOEX
:/my search query\zs
:a
my text to insert
.
:x
EOEX
This will find the first selection that matches regex specified by :/, place the cursor at the location specified by \zs, and enter insert mode after the cursor.
You can move \zs to achieve different results. For example:
ex $yourfile <<EOEX
:/start of match \zs end of match
:a
my text to insert
.
:x
EOEX
This will change the first occurrence of "start of match end of match" to "start of match my text to insert end of match".
If you want to allow any amount of whitespace in your searches between keywords, use \_s*. For example, searching for a function that returns 0: :/\_s*return\_s*0}
If you are wanting to see the work being done inside vim or gvim you can use --remote-send
gvim --servername SHELL_DRIVER
bashpromt# cat mybash.sh
#!/bin/bash
echo "about to open $1"
gvim --servername SHELL_DRIVER $1 #I need to use vim application to open a file
#now write something into file.txt and close it
gvim --servername SHELL_DRIVER --remote-send '<ESC>i something to the file<ESC>:wq<CR>'
echo "done."
This will be slow but will do what you want it to.
First we open a gvim in which we can open all of our files (for efficiency)
With the first gvim line we open the file in the previously opened gvim.
On the second gvim line we send a command to the previously opened instance of gvim (with the desired file still open).
The command is as follows:
<ESC> - get out of any mode that gvim might have been in
i something to the file - go into insert mode and type " something to the file"
<ESC> - exit insert mode
:wq - write the file and quit vim
Recently, I have answered a similar question, “Automated editing
of several files in Vim”. May be the solution that I describe there
will satisfy your needs.
Related
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.
I accidentally ran the following command in my console.It was a copy paste error.
vim -> /etc/apache2/sites-available/25-xyz-https.conf.
But after that my 25-xyz-https.conf got corrupted. Eventhough I recovered the file just curious to understand what has happened.
This happens:
vim -
means open stdin in vim.
> file
is an output redirection by the shell. Stdout of the (vim) process will get stored in file. file will get truncated by the shell before the (vim) process get's started.
I recommend to always put a # into the shell before pasting things into the shell. That gives you a chance to review the line before executing it, especially if you paste the line together with the line break at the end. (which would execute it right away)
The shell ran "vim -" and then redirected the output from that command to /etc/apache2/sites-available/25-xyz-htttps.conf
If you run "vim -" you'll see it do something like this:
Vim: reading from stdin...
You will have to hit ^C to break out of reading from stdin, then :q to exit vim.
This is because many utilities interpret the '-' character as stdin (or stdout, depending on the context).
If you did something like:
date | vim -
This would open 'vim' with the contents of the document showing the current date. There is no open file, you could not simply :w to save the file, but you could :w./thedate.txt to save the contents to ./thedate.txt. The important thing is that the output of the 'date' command became the input to the 'vim' command.
After that, the > character just redirects stdout from the whole "vim -" session to overwrite the file provided.
I want to script vim to edit files from the command line. For example I want to do something along the lines of:
vim -<SOME_OPTION> 'Iworld<Esc>bIhello <Esc>:wq helloworld.txt<CR>'
or:
echo 'Iworld<Esc>bIhello <Esc>:wq helloworld.txt<CR>' | vim
and have it save the file helloworld.txt with a body of hello world
Is this possible? I've tried a few different approaches but none seem to do it. I realize I can do things like vim +PluginInstall to run Ex commands from the command line, but I'd love to be able to string together arbitrary motions
This can be achieved with the + flag and the :normal command:
$ vim +"norm Iworld" +"norm Ihello " +"wq helloworld.txt"
I think what you are looking for is vim's -w/W and -s {scriptin} option. Well in your case you should make a scriptfile, and with -s file to let vim execute all your "key presses"
I think vimgolf has used these options too.
Suppose that I have a command, say find ABCD | grep text1 which outputs full-path of a file to be opened. I know I can send this output to vim using xargs and open the file, but this is possible only in command line.
How can I do this from inside vim editor?
Assuming COMMAND returns exactly the path of your file, then something like this should be ok from the command line:
$ vi $(COMMAND)
and this should be ok from within vim:
:e `COMMAND`
Is it possible to configure VIM in a such way that if I type
vim filename:123:89
it opens file filename goes to line 123 and column 89?
If not through VIM maybe with a hack for the shell?
You can install the file-line plugin to open a file to the line and column specified after the filename. (github mirror)
From the Readme on github
When you open a file:line, for instance when coping and pasting from
an error from your compiler vim tries to open a file with a colon in
its name.
Examples:
vim index.html:20
vim app/models/user.rb:1337
With this little script in your plugins folder if the stuff after the colon is a number and a file exists with the name especified before the colon vim will open this file and take you to the line you wished in the first place.
I'm not sure how to skip to the column, but I've wanted the same feature for ages, so I just hacked up the "jump to line" functionality. In your .bashrc, set
VIM=$(which vim)
function vim {
local args
IFS=':' read -a args <<< "$1"
"$VIM" "${args[0]}" +0"${args[1]}"
}
This splits the argument to Vim by :, then constructs a command line of the form
vim <filename> +0<line>
The +0 is a hack to make sure the default line number is zero.
(If you're not using Bash, you can adapt this into a script and put it in your path, or translate it to your favorite shell language. To edit filename:with:colons, use $VIM.)
I've been using the file-line plugin, but it has a few open issues, and breaks some other vim plugins. So I went fishing for a better solution. Here it is:
function vim() {
local first="$1"
case $first in
*:*)
shift
command vim ${first%%:*} +0${first##*:} $#
;;
*)
command vim $#
;;
esac
}
Limitations:
bash only
Only parses first argument, whereas vim +X parses the first file argument. A more complex version could easily be made with proper command line parsing.
Advantages:
doesn't break other vim plugins
you could easily use $EDITOR and use this with emacs for instance.
compared to Fred's answer it doesn't use IFS/read to parse the argument but uses bash parameter expansion.
also sends in the remaining argument, which might occasionally be necessary.