Automate a Vim script to write text to a file - vim

I am writing a script that runs on the command line and I want to be able to automatically append some static text to a file using Vim.
This is a simplified version of what I have:
insert_text() {
vim -s ./text.txt new.txt;
}
Then it would run on the command line by typing insert_text. Inside text.txt I have tried things such as:
iSome Text:wq
This puts me in insert mode and writes the text but I don't know how to leave insert mode in this way. The :wq never works and is instead written to the new.txt.

If you just want to append text to a file you don't need any special tools. For instance you can just use:
echo "Some text" >> myfile.txt
or if you have a large block of text
>>myfile.txt cat <<EOF
some
long
block of text
EOF
If you want it at the start of a file you can use a temporary file to do this. For instance:
echo "Some Text" | cat - myfile.txt > /tmp/file && mv /tmp/file myfile.txt

This will append someText at the beginning of line 1:
vim -c "1 s/^/someText" -c "wq" test.txt
When you run a command from the terminal and you want Vim to exit after that, instead of :wq do +wq. For example:
vim +'SomeCommand' +qa

Related

How can I give special command (insert) to vi?

I remember doing magic with vi by "programming" it with input commands but I don't remember exactly how.
My sepcial request are:
launch vi in a script with command to be executed.
do an insert in one file.
search for a string in the file.
use $VARIABLE in the vi command line to replace something in the command.
finish with :wq.
I my memory, I sent the command exactly like in vi and the ESC key was emulate by '[' or something near.
I used this command into script to edit and change files.
I'm going to see the -c option but for now I cannot use $VARIABLE and insert was impossible (with 'i' or 'o').
#!/bin/sh
#
cp ../data/* .
# Retrieve filename.
MODNAME=$(pwd | awk -F'-' '{ print $2 }')
mv minimod.c $MODNAME.c
# Edit and change filename into the file (from mimimod to the content of $VARIABLE).
vi $MODENAME.c -c ":1,$s/minimod/$MODNAME/" -c ':wq!'
This example is not functionning (it seems the $VARIABLE is not good in -c command).
Could you help me remember memory ;) ?
Thanks a lot.
Joe.
You should not use vi for non-interactive editing. There's already another tool for that, it's called sed or stream editor.
What you want to do is
sed -i 's/minimod/'$MODNAME'/g' $MODNAME.c
to replace your vi command.
Maybe you are looking for the ex command, that can be run non-interatively:
ex $MODENAME.c <<< "1,\$s/minimod/$MODNAME/
wq!
"
Or if you use an old shell that does not implement here strings:
ex $MODENAME.c << EOF
1,\$s/minimod/$MODNAME/
wq!
EOF
Or if you do not want to use here documents either:
echo "1,\$s/minimod/$MODNAME/" > cmds.txt
echo "wq!" >> cmds.txt
ex $MODENAME.c < cmds.txt
rm cmds.txt
One command per line in the standard input. Just remember not to write the leading :. Take a look at this page for a quick review of ex commands.
Granted, it would be better to use the proper tool for the job, that would be sed, as #IsaA answer suggests, or awk for more complex commands.

How can I start vim by inserting the date and some text at the beginning of the file?

I'm working on a bash script to create log files something like this, where the latest entry appears first in file:
2019-07-26 Looks like SSD needs replacing
2019-07-25 db backup failed
If no text is included on command line, just start vim.
If text is included on the command line, insert date and that text, e.g.
edlog db backup failed
Conceptually it looks like this in my head but only the first -c command works as expected:
!/bin/bash
if [ $# -eq 0 ]
then
nvim ~/log.txt
else
# :r will Insert date at top of file.
# $\t moves to end of line and inserts a tab
# $* appends contents of command line
nvim -c ":r! date +\%F" -c "$\t" -c "$*" ~/log.txt
fi
Here's my solution. I'm very much open to criticism and corrections.
#!/bin/bash
# Appends to a log file if you type a message, or
# just brings up vim in case you want to log several
# lines' worth
# Nothing added to command line, so just bring up vim:
if [ $# -eq 0 ]
then
nvim ~/Dropbox/log.txt
else
# User entered something like this:
# edlog Extra backup last night due to OS update
LINE=" $*"
# Format date like 07/25/2019
# Start inserting text after the date.
# Insert all arguments on command line, like "Re-test db"
# Then write out file, and quit back to shell
nvim -c ":pu=strftime('%m/%d/%Y')" -c ":startinsert!" -c "norm a$LINE" -c "wq" ~/Dropbox/log.txt
fi
A quasi-vim centric solution:
date > file
echo "$#" >>file
vim file +'0join'
Using vim commands:
vim +'0r !date' +'0d' +"normal! A<Tab>$#"
Where <Tab> is a literal tab character.
Or with ex:
ex <<EOF file
0r !date
0d
normal! A<Tab>$#
wq
EOF

Linux vi File Contents Modifying

Suppose I have these in a file called test:
u001:x:comp111:mark_henry
u002:x:comp321:zack_mike
u003:x:comp132:chris_white
And I want to open that file go to the line that has chris_white and change it to chris_brown so it becomes u003:x:comp132:chris_brown. I'm thinking to use the sed command to do so but I'm not sure how.
Using sed, below method can replace all occurrences of chris_white to chris_brown without opening the file test.
sed -i -e 's/chris_white/chris_brown/g' test
If you want to open the file test in vi editor and replace, then follow the below steps,
1) vi test
2) Type :%s/chris_white/chris_brown/g
3) Press Enter
This will replace all occurrences of chris_white to chris_brown in your file test.
With vi you need more effort than with the basic ed.
echo "s/chris_white/chris_brown/
w
q" | ed -s test
You can use printf for writing the lines as parameters:
printf "%s\n" "s/chris_white/chris_brown/" w q | ed -s test

how to open a text file with an editor on append mode

If I do this:
touch newfile.txt
sudo chattr +a newfile.txt
I can then add content to that file using:
echo "Hello world" >> newfile.txt
Is there away I can do the above with a text editor such as vim, gedit, etc?
Note that opening the this file the normal way with text editors will fail when trying to save.
You can simply open a plain vim session and then save your text with
:w >> newfile.txt

Execute a command within Vim from the command line

Is there a way to execute a Vim command on a file from the command line?
I know the opposite is true like this:
:!python %
But what if I wanted to :retab a file without opening it in Vim? For example:
> vim myfile.c
:retab | wq
This will open myfile.c, replace the tabs with spaces, and then save and close. I'd like to chain this sequence together to a single command somehow.
It would be something like this:
> vim myfile.c retab | wq
This works:
gvim -c "set et|retab|wq" foo.txt
set et (= set expandtab) ensures the tab characters get replaced with the correct number of spaces (otherwise, retab won't work).
I don't normally use it, but vim -c ... also works
The solution as given above presumes the default tab stop of eight is appropriate. If, say, a tab stop of four is intended, use the command sequence "set ts=4|set et|retab|wq".
You have several options:
-c "commands" : will play Ex commands as you entered them in the command line.
In your example : vim myfile -c 'retab | wq'. This is what Firstrock suggested.
-S "vim source file" : will source given vim script
(like running vim -c "source 'vim source file'"):
If you have a file script.vim containing:
retab
wq
Then you can use vim myfile.c -s script.vim (the extension does not really matter)
-s "scriptin file": will play contents of file as it contains normal mode commands: If you have script.txt containing:
:retab
ZZ
with end of lines consisting of a single ^M character (for example you saved the script using the :set fileformat=mac | w), then you can run: vim myfile.c -S script.txt (ZZ is another way to exit vim and save current file).
Note that you can record those scripts with vim my_file -W script.txt, but it suffers a bug if you happen to use gvim (the GUI).
Not a direct answer to your question, but if you want to replace tabs with spaces (or do any other regex search/replace) for a list of files, you can just use in-place sed search/replace:
sed -i 's/\t/ /g' foo1.txt foo2.txt
or
ls *.txt | xargs sed -i 's/\t/ /g'
(In this example I am replacing each tab character with three spaces.)
NOTE: the -i flag means operate in-place.
From the sed man page:
-i[SUFFIX], --in-place[=SUFFIX]
edit files in place (makes backup if extension
supplied)

Resources