Showing posts with label Text editing. Show all posts
Showing posts with label Text editing. Show all posts

Thursday, 7 September 2017

A useful sample .exrc file for vi

In this article I'd like to share a sample .exrc file which I've begun to use while working with the vi text editor on UNIX systems. It lacks the extreme level of customization available with vim and is more of a minimal vim version.

The .exrc file is to be placed within the users' home directory and the mentioned settings will get loaded every time the user uses vi to edit a file.

So, here's the file:

[ssuri@myserver:~] $ cat .exrc
" Show whitespace and EOL characters
" set list
" Show line numbers
set nu
" Hide Line Numbers
" set nonu
" Show matching brackets
set showmatch
" Show current mode in status line
"show current editor mode
set showmode
"set autoindentation in scripts
set autoindent
"map S to :wq! key combination
map S :wq!
"set searches to case insensitive
set ignorecase
"set shell env for ! commands
set shell=/bin/bash
"show matching braces
set showmatch


Comments are indicated y double quotes ("). 
Note: I've observed that this file does not tolerate blank lines. So if you'd like to keep some blank lines in the file to make it more readable, be sure to place " at the start of the line.

Wednesday, 30 August 2017

Removing files with spaces in their names in Linux (using IFS)

In UNIX it's uncommon to have files with spaces but it can happen. Consider a situation wherein I have a couple of space separated files and I'd like to remove some of them.

[root@pbox test]# ls -l
total 0
drwxr-xr-x. 2 root root 6 Aug 30 14:25 abc
drwxr-xr-x. 2 root root 6 Aug 30 14:25 def
-rw-r--r--. 1 root root 0 Aug 30 14:17 my file 1
-rw-r--r--. 1 root root 0 Aug 30 14:17 my file 2
-rw-r--r--. 1 root root 0 Aug 30 14:17 my file 3
-rw-r--r--. 1 root root 0 Nov  7  2017 my file 4
-rw-r--r--. 1 root root 0 Nov  7  2020 my file 5
-rw-r--r--. 1 root root 0 Nov  7  2017 my file 6
-rw-r--r--. 1 root root 0 Aug 30 14:24 my file 7

I'd like to remove files modified in the month of August.

[root@pbox test]# ls -l |grep -i ^-|grep -i Aug
-rw-r--r--. 1 root root 0 Aug 30 14:17 my file 1
-rw-r--r--. 1 root root 0 Aug 30 14:17 my file 2
-rw-r--r--. 1 root root 0 Aug 30 14:17 my file 3
-rw-r--r--. 1 root root 0 Aug 30 14:24 my file 7


Now if I try to run the for loop to iterate over the required files I get an unexpected result because of the spaces:

[root@pbox test]# for i in $(ls -l |grep -i ^-|grep -i Aug| awk '{print $9, $10, $11}') ; do echo "$file to remove is $i" ; done
 to remove is my
 to remove is file
 to remove is 1
 to remove is my
 to remove is file
 to remove is 2
 to remove is my
 to remove is file
 to remove is 3
 to remove is my
 to remove is file
 to remove is 7


This is because the default input field separator is a space character so whenever the for loop sees a space it treats the following string as a new field.

To fix this we'll modify our input field separator by changing the value of the IFS variable.


[root@pbox test]# IFS=$'\n'
[root@pbox test]# for i in $(ls -l |grep -i ^-|grep -i Aug| awk '{print $9, $10, $11}') ; do echo "$file to remove is $i" ; done
 to remove is my file 1
 to remove is my file 2
 to remove is my file 3
 to remove is my file 7
[root@pbox test]#

Now instead of doing an echo if we'd like to remove the files we could simply type the following:

[root@pbox test]# for i in $(ls -l |grep -i ^-|grep -i Aug| awk '{print $9, $10, $11}') ; do rm $i ; done
rm: remove regular empty file ‘my file 1’? y
rm: remove regular empty file ‘my file 2’? y
rm: remove regular empty file ‘my file 3’? y
rm: remove regular empty file ‘my file 7’? y

And the files are now gone.

[root@pbox test]# ls -ltr
total 0
drwxr-xr-x. 2 root root 6 Aug 30 14:25 def
drwxr-xr-x. 2 root root 6 Aug 30 14:25 abc
-rw-r--r--. 1 root root 0 Nov  7  2017 my file 4
-rw-r--r--. 1 root root 0 Nov  7  2017 my file 6
-rw-r--r--. 1 root root 0 Nov  7  2020 my file 5

Add a new line after a string match using vim or sed

In this brief article I'd like to demonstrate how we can add a new line after a character match using vim and sed.

Let's take an example scenario where I have a file comprised of the 'ls -l' output of the /etc/ directory and I would like to insert a new line between each line in the command output.

My file looks like this:

[ssuri@:~] $ cat dir_list | head
drwxr-xr-x.  2 root  root    4096 Jan 11  2010 popt.d
drwx------.  2 root  root    4096 Jun  3  2011 cron.weekly
drwxr-xr-x.  3 root  root    4096 Jan 16  2014 pkcs11
drwxr-xr-x.  2 root  root    4096 May  7  2014 gnupg
drwxr-xr-x.  3 root  root    4096 Jun 19  2014 hal
drwxr-xr-x.  5 root  root    4096 Dec 12  2014 pm
drwxr-xr-x.  3 root  root    4096 Dec 12  2014 xdg
drwxr-xr-x.  2 root  root    4096 Dec 12  2014 makedev.d
drwxr-xr-x.  3 root  root    4096 Dec 12  2014 sane.d
drwxr-xr-x.  2 root  root    4096 Dec 12  2014 redhat-lsb


First let's insert a new line using vim. The vim command used here is :%s/^drw/\rdrw/g

The output of this vim command will modify the file as follows:


  2 drwxr-xr-x.  2 root  root    4096 Jan 11  2010 popt.d
  3
  4 drwx------.  2 root  root    4096 Jun  3  2011 cron.weekly
  5
  6 drwxr-xr-x.  3 root  root    4096 Jan 16  2014 pkcs11
  7
  8 drwxr-xr-x.  2 root  root    4096 May  7  2014 gnupg
  9
 10 drwxr-xr-x.  3 root  root    4096 Jun 19  2014 hal
 11
 12 drwxr-xr-x.  5 root  root    4096 Dec 12  2014 pm
 13
 14 drwxr-xr-x.  3 root  root    4096 Dec 12  2014 xdg
 15
 16 drwxr-xr-x.  2 root  root    4096 Dec 12  2014 makedev.d
 17
 18 drwxr-xr-x.  3 root  root    4096 Dec 12  2014 sane.d
 19
 20 drwxr-xr-x.  2 root  root    4096 Dec 12  2014 redhat-lsb

(Don't mind the line numbers. they're just there because I had the set nu flag on to show line numbers)

Let me break down the expression for you.

% -> operates on the entire file.
s  -> search for an expression.
^drw -> search for lines beginning with the string drw.
\rdrw -> \r is the carriage return. In vim this will insert a new line. 
g -> Perform a global search and replace.


So, the expression %s/^drw/\rdrw/g will walk through the entire file, look for the lines beginning with the string drw and replace them with a new line followed the line beginning with the string drw throughout the file.


Using vim is great but you'll have to manually edit the file. So let's look at sed if you'd like to accomplish this task within a script.


[ssuri@:~] $ sed 's/^drw/\ndrw/g' dir_list

drwxr-xr-x.  2 root  root    4096 Jan 11  2010 popt.d

drwx------.  2 root  root    4096 Jun  3  2011 cron.weekly

drwxr-xr-x.  3 root  root    4096 Jan 16  2014 pkcs11

drwxr-xr-x.  2 root  root    4096 May  7  2014 gnupg

drwxr-xr-x.  3 root  root    4096 Jun 19  2014 hal

drwxr-xr-x.  5 root  root    4096 Dec 12  2014 pm

drwxr-xr-x.  3 root  root    4096 Dec 12  2014 xdg

drwxr-xr-x.  2 root  root    4096 Dec 12  2014 makedev.d

drwxr-xr-x.  3 root  root    4096 Dec 12  2014 sane.d

drwxr-xr-x.  2 root  root    4096 Dec 12  2014 redhat-lsb


The sed expression is very similar to the expression we used in vim the only difference being that in case of sed we'll use \n to insert a new line instead of \r.

I hope this article was useful to you and I thank you for reading.

Tuesday, 24 January 2017

Using AWK for column insertion within a text file

At times we may come across a requirement for inserting a column or maybe an entire file within another file. If the requirement is to merge the two files such that the columns of the second file commence right after the last column of the first file, then we can easily accomplish that using paste or join commands. But the task becomes tricky if the files are of different length columns and do not have a common column among them.
This article gives a quick demo about how we can use awk to add a new column/file to an existing file.

So, we have two files f1 & f2.

[root@alive ~]# cat f1
test1 testA
test2 testB
test3 testC
test4 testD
[root@alive ~]# cat f2
test7 testE
test8 testF
test9 testG
test10 testH


We want to merge file f2 with file f1 such that we would basically be adding two new columns to the file f1.

Here is the awk code to accomplish this task:

 awk '{getline new_col < "f2"} {print $0, new_col}' f1

The resulting output is as follows:

test1 testA test7 testE
test2 testB test8 testF
test3 testC test9 testG
test4 testD test10 testH


In the above example I used $0 with the awk print statement to print all columns of file f1 first followed by those belonging to file f2. We could've easily inserted the columns belonging to file f2 into some individual columns of file f1 by using individual column numbers instead of $0 in the print statement. Here's an example:

 awk '{getline new_col < "f2"} {print $1, new_col, $2}' f1

This awk statement will print the first column of file f1 first followed by the two columns comprised in file f2 and then the second column from file f1.

test1 test7 testE testA
test2 test8 testF testB
test3 test9 testG testC
test4 test10 testH testD

I hope this article was helpful and will definitely try to keep posting more tips & tricks like this in the future.

Sunday, 15 January 2017

Using AWK to match columns from multiple files

I came across an interesting requirement at a facebook forum today. The requirement was to match columns two & three of one file with columns one & two of another file & print the entities from the first file which do not have nay matches.

Here are the files:

[root@alive ~]# cat file1
d1,40,gold
d2,30,silver
d3,20,bronze
d4,10,iron
d5,5,wood
d6,20,gold
d7,10,wood
d8,5,gold
d9,10,silver
[root@alive ~]# cat file2
gold,40
silver,30
bronze,20
iron,10
wood,5

The AWK one liner that works is:

awk -F',' 'NR==FNR{c[$1$2]++;next};!c[$3$2]' file2 file1

The following will be the output of he above AWK statement:

d6,20,gold
d7,10,wood
d8,5,gold
d9,10,silver


Now, let's do a step by step breakdown of what just happened.

-F ',' 
(The file columns are comma separated. So we changed the field separator)

NR==FNR 
(When you have two input files to awk, FNR will reset back to 1on the first line of the next file whereas NR will continuing increment from where it left off. By checking FNR==NR we are essentially checking to see if we are currently parsing the first file.)
 
c[$1$2]++;next
(Here we are parsing the first file file2 creating an associative array with columns one & two & post increment the value by one. The next command tells AWK not to process any further commands and proceed to next record.)

!c[$3$2] 
(This line only executes when FNR==NR is false, i.e. we are not parsing file2 and thus must be parsing file1. We then use the first fields $2 and $3 of file1 as the key to index into our 'seen' list created earlier.  If the value returned is 0 it means we didn't see it in file1 and therefore we should print this line. Conversely, if the value is non-zero then we did see it in file1 and thus we should not print its value. Note that !c[$2$3] is equivalent to !a[$2$3]{print} because the default action when one is not given is to print the entire line.)

In case the requirement changes and we needed to print the matching lines instead of those that didn't match, we'd modify our AWK expression as follows:


awk -F',' 'NR==FNR{c[$1$2]++;next};c[$3$2]' file2 file1

And the resulting output will be:

d1,40,gold
d2,30,silver
d3,20,bronze
d4,10,iron
d5,5,wood

I hope this has been an interesting AWK read.

Thursday, 17 November 2016

AWK cheat sheet


Similar to the sed cheat sheet I shared in the previous article here, this article will be an awk cheat sheet. All the examples illustrated here may not be entirely original as this is something I've compiled over the years while using awk. Without any further ado, here it goes:



AWK ExpressionDescription
awk '/l.c/{print}' /etc/hosts [do a regex match with string containing 1 cahrector b/w l & c]
awk '/l*c/{print}' /etc/hosts [regex match everything b/w charectors l & c]
awk '/[al1]/{print}' /etc/hosts [a regex match with strings containing charectors a,l or l in a line]
awk '/[0-9]/{print}' /etc/hosts [prints all lines with numbers in them]
awk '/^10./ {print}' /etc/hosts [print all lines beginning with number 10]
awk '/rs$/{print}' /etc/hosts [print all lines ending with rs]
awk '/\$25.00/{print}' somedta.txt [escaping the $ character]
awk '//{print $1, $2, $3; }' somedta.txt [print columns 1,2 & 3 with fields separated by a space]
awk '//{printf "%-10s %s\n",$2, $3 }' my_shopping.txt [imporves spacial formatting between fields]
awk '/ *\$[2-9]\.[0-9][0-9] */ { print $1, $2, $3, $4, "*" ; } / *\$[0-1]\.[0-9][0-9] */ { print ; }' food_prices.list[multiple pattern matches & awk commands separateed by ;]
"awk '/ *\$[2-9]\.[0-9][0-9] */ { printf ""%-10s %-10s %-10s %-10s\n"", $1, $2, $3, $4 ""*"" ; } / *\$[0-1]\.[0-9][0-9] */ { printf ""%-10s %-10s %-10s %-10s\n"", $1, $2, $3, $4; }' somedta.txt
"[use printf for improved formatting]
awk '/ *\$[2-9]\.[0-9][0-9] */ { print $0 "*" ; } / *\$[0-1]\.[0-9][0-9] */ { print ; }' somedta.txt [value $0 denotes entire line with awk]
awk '$3 <= 30 { printf "%s\t%s\n", $0,"**" ; } $3 > 30 { print $0 ;}' somedta.txt[match value of 3rd column & print result accordingly]
awk '($3 ~ /^\$[2-9][0-9]*\.[0-9][0-9]$/) && ($4=="Tech") { printf "%s\t%s\n",$0,"*"; } ' somedta.txt[example of using multiple conditions in single awk command]
awk '$4 <= 20 { printf "%s\t%s\n", $0,"*" ; next; } {print $0 ;}' somedta.txt[add a * at the end of the line if value in 4th column is less than or euqal to 20]
ls -l | awk '$3 != "sahil" {print}' [print files not owned by user sahil]
uname -a | awk 'hostname = $2 {print hostname}' [using variables. assigned value of 2nd field to a variable named hostname]
awk '/^example.com/ { counter=counter+1 ; printf "%s\n", counter ; }' somedta.txt [use numeric variable in a for loop to count occurrances of lines beginning with techmint.com]
awk '/^example.com/ { counter=counter+1 ;} END {printf "%s\n", counter ; }'somedta.txt [print only total number of times example.com occurs in file]
awk 'BEGIN {count=0} /^example.com/ {count+=1} END {printf "%s\n", count ;}'somedta.txt [result is same as above example but here we've used begin & end both]
ls -l | grep ^- | awk 'BEGIN {total=0} {total+=$5} END {print total/1024/1024}' [print the total size of files in current directory in MB]
awk 'BEGIN {print "this is a begin Test"} /^example.com/ { counter=counter+1 ;} END { printf "%s\n", counter ; }'somedta.txt [using begin & end. begin is executed before input lines are read. END is executed after all input lines are read]
awk '{print FILENAME}'somedta.txt [FILENAME is a built in which stores the file name. This awk command will print the file name as many times as the number of lines in the file]
awk '{print NR, "has", NF, "fields" $1}'somedta.txt [NR is number of records/rows. NF is the number of fields/columns]
awk ' END { print "Number of records in file is: ", NR } 'somedta.txt [print total number of rows]
awk -F':' '{ print $1, $4 ;}' /etc/passwd [change input filed separater]
awk -F':' '$1 == "sahil" {print}' /etc/passwd [match user sahil in passwd file & print the matching line]
awk -F':' '/sahil/ {print "user", $1,"has shell", $7}' /etc/passwd [search for user sahil in passwd file & print user name & shell]
awk -F':' '{if($1 == "sahil") print ;}' passwd [does the same as above example but using if condition]
awk -F';' '{if ($1 == "12345") {$6 = 5000;} {OFS = ";"} {print $0;}}' file.txt[if 1st column has value 12345 then change value of 6th column to 5000]
awk ' BEGIN { FS=":" ; } { print $1, $4 ; } ' /etc/passwd [change input field separater 2nd method]
awk -F':' ' BEGIN { OFS="==>" ;} { print $1, $4 ;}' /etc/passwd [change input & output field separater]
user=root ; awk "/$user/ {print}" /etc/passwd [use shell variable in an awk statement]
awk 'BEGIN{ for(count=0;count<=5;count++){ print "sometext"} }' [for loop in awk. This prints the string sometext 5 times to stdout]
awk 'IGNORECASE = 1; /SaHil/ {print ;}' somedata.txt [do a case insensitive search with AWK]
echo "sahil" | awk '{print substr ($1,1,2)}' [use substring function in awk to chop off part of a string]
awk 'sub ("example.com", "test.com",$1)'somedta.txt [replace all occurances of example.com in 1st column with sahil.com]
"awk 'BEGIN {count=0}
{ if($1 == ""example.com"")
{count++}
if(count == 3)
{ sub(""example.com"",""UNIX"",$1)}}
{ print $0}' somedta.txt
"[replace 3rd occurance of example.com with UNIX]
awk '{if ($NR%2 ==0) {print $0, "\n TESTLINE"} else {print $0}}' somedta.txt [insert the word TESTLINE in a newline after every line]
awk 'NR >3 && NR < 6 {print}' somedta.txt[print line number 4 & 5 from the file]
awk '!/^$/' somedta.txt [remove blank lines from a file]
awk 'NR%2{printf "%s ",$0;next;}1' somedta.txt[join 2 line. replace newline with a space]
awk '{printf $0;printf " "}NR % 2 ==0 {print " "}' somedta.txt[join 2 line. replace newline with a space]
awk '{printf $0;printf " "}NR % 3 ==0 {print " "}' somedta.txt[join 3 line. replace newline with a space]
awk '{ print $NF }' somedta.txt [print last column in a file]
df -hTP | awk '{gsub(/%/,"")}1 {print $1,$6}' [Replace the % character with a space from df -h output]
df -hTP | awk '{gsub(/%/,"",$6)}1 {print $1,$6}' [Replace the % character with a space from df -h output limited to 6th column]

SED cheat sheet


This article is exactly what the title says. It's a cheat sheet. IF you are looking for information how to learn to use sed with detailed explanation of the usage examples then this article is not the best avenue. However, if you are looking for a lot of usage examples with brief descriptions then this is the right place.



SED ExpressionDescription
sed 's/sahil/{&&&}/' somedata.txt [put the matched string in parenthesis & replicate it as many times as & is specified]
sed '2,3 s/sahiltech/Admin/' somedata.txt [replace string on 2nd & 3rd line. If there is a $ after , then replace till last line]
sed '/linux/ s/unix/Admin/' somedata.txt [do replace on lines matching a pattern]
sed -n '5,10p' somedata.txt [print lines 5 to 10 only]
sed '20,35d' somedata.txt [print the file omitting lines 20 to 35]
sed -n -e '5,7p' -e '10,13p' somedata.txt [print non consecutive line ranges]
sed 's/version/story/gi' somedata.txt [case insensitive search & replace]
ip route show | sed 's/  */ /g' [replace multiple blank spaces using a single space]
sed '30,40 s/version/story/g' somedata.txt [search & replace within a given range of lines]
sed 's/[Zz]ip/rar/g' somedata.txt [using regex in search & replace]
sed -n '/^Jul 1/ p' /var/log/secure [view lines containing a given pattern]
sed -e '/^#/d' -e '/^$/d' somedata.txt [remove comments & blank lines]
sed 'G;G' somedata.txt [inset 2 blank lines between each lines]
sed '0~2 a\\' somedata.txt | tr -d '\\' [insert a blank line after every 2 lines]
sed -i'.orig' 's/this/that/gi' somedata.txt [take backup of orignal file as filename.orig & perform replace on original file]
sed -i 's/old/new/g' somedata.txt [modify original file]
sed -ibak 's/old/new/g' somedata.txt [backup & modify original file]
sed -n 's/old/new/gpw output' somedata.txt [write changes to new file called output]
sed 's/\-.*//g' somedata.txt [empty everything after the - charector]
sed 's/...$//' somedata.txt [delete last 3 charectors from each line]
sed -e 's/#.*//' somedata.txt [eliminate comments from a file]
sed -e 's/#.*//;/^$/d' somedata.txt [eliminate comments & empty lines from a lines, -e to execute multiple sed commands separated by ;]
sed -e '1w out' -e ' 2w out' -e ' $w out' somedata.txt [wwrite 1st, 2nd & last line to new file called out]
sed '1,5w out' somedata.txt [write lines 1 to 5 to a file out]
sed -n -e '/Storage/w output.txt' somedata.txt [write lines with pattern Storage to a new file]
sed -n '/Storage/,+2w output.txt' somedata.txt [write lines matching pattern plus next two lines to a new file]
sed '1,3 s/^/hello: \t/g' somedata.txt [add hello to the start of 1st 3 lines]
sed -e '4d' -e '2d' somedata.txt [delete 4th & 2nd line from file]
sed -n -e '/Software/p' -e '/Storage/p' somedata.txt [search & print matching pattern only]
sed -e '1d' -e '$d' -e '/^$/d' somedata.txt [delete 1st, last & all blank lines]
sed 's/\([^:]*\).*/\1/' /etc/passwd [extract usernames from password file]
sed '3 a Cool gadgets and websites' somedata.txt[append a line after the 3rd line of file]
sed '/vsun001*/a still testing sed' somedata.txt [insert line after every line with matching patter]
sed '2 i this is sed insert test' somedata.txt [insert a line before 2nd line of file]
sed '/vsun001*/i insert testing' somedata.txt [insert a line before every line matching the pattern]
sed '/this is/c is this a test' somedata.txt [replace lines mathing pattern 'this is' with line 'is this a test']
sed '2c not found' somedata.txt [replace 2nd line in file somedata.txt with the line not found]
sed '=' somedata.txt [print line number above line being printed]
sed -n '/vsun0012/=' somedata.txt [print line number containing the pattern vsun0012]
sed 's/0\{3\}//g' somedata.txt [remove 3 zeros from numbers in the file. For example, 7.000 will become 7.]
sed '0~3 s/$/\nMy Text/g' somedata.txt [insert the line My Text after every 3 lines. In 0~3, 0 is the first addition & 3 denotes after how many lines the subsequent text is to be inserted]
sed 's/.\{2\}/&#/g' somedata.txt [insert a # character after every 2 characters in the file]
sed 'N;s/\n/ /g'[join 2 line. replace newline with a space]
sed 'N;N;s/\n/ /g'[join 3 consecutive lines]
sed -e '{N;s/\n/@/}' somedata.txt[join 2 consecutive lines & place a @ symbol b/w the lines]
sed 's/sahil/Linux Admin/2g' somedata.txt [replace from 2nd occurnace till end of line in the file]

Wednesday, 26 October 2016

My VI cheat sheet


The VI editor is an indispensable tool for any UNIX system administrator. In this post I'd like to share some of the common vi commands & options that I use or try to use on a routine basis.


Leaving vi:

shift +zz -> write & quit.
wq -> write & save
q! -> quit without saving.
:w filename -> save ac copy of the currently open file with a new name.


vi modes:

command mode -> aAiIoOc -> inset mode
command mode  <- ESC <- insert mode
command mode -> : ! / ? -> promtpt/ex mode
command mode <- press enter <- promtpt/ex mode


Copying command sequences:

Copy an example command sequence: jhhkkkkll
The commands get copied to OSs' clipboard
Open a file in vi & while in command mode right click to paste the copied command sequence.
The result is that vi executes the command sequence.

Open multiple files for editing in a single vi command:

:n -> go to next file
:N -> go to previous file
:rew -> rewind to first file.
:r -> read a file into current file.



Basic cursor movement:

h -> move cursor left
l -> move cursor right
j -> down 1 line from current character
k -> up 1 line from current character

Moving around b/w text:

w -> forward a word
b -> backward a word
e -> forward to end of current word
) -> forward a sentence
( -> backward a sentence
} -> forward a paragraph
{ -> backward a paragraph

Note:
vi assumes end of sentences by . & paragraph changes by blank lines.
You can prefix a number before the movement commands


Moving by lines:

^ -> move cursor to beginning of current line
0 -> move cursor to beginning of current line
$ -> move cursor to end of current line
1G -> move to first line
G -> move to end of file
nG -> move to nth line of file
% -> matching paren/braces
ctrl+g -> display file status & line number


Scrolling:

ctrl+d -> scroll down half a screen
ctrl+u -> scroll up half a screen
ctrl+f -> scroll forward by a screen
ctrl+b -> scroll backward by a screen


Inserting text:

i -> insert before cursor
I -> insert at beginning of line
a -> append after cursor
A -> append at the end of line
o -> open a new line below current line
O -> open a new line above current line

File Management:

:w -> write without quitting
:q -> quit without writing.
:q! -> quit without saving changes.


Deleting text:

x -> delete current character
dd -> delete current line
dw -> delete current word
d^ -> delete to beginning of line
d$ -> delete to end of line

Note:
You can prefix a number before the deletion commands


Changing text:

r -> r followed by character replaces current character with the character typed with r
R -> override mode i.e the characters you type replace the characters already present on the cursor prompt.
~ -> changes case of current characters on the cursor


Undo, redo & repeat:

u -> undoes last change
ctrl+r -> redoes last change (undoes undo)
U -> undoes all changes on current line
. -> repeats last change


Delete, yank & put:

dd -> delete (cut) the line
yy -> copy the line
dx -> delete an amount
yx -> copy an amount
y$ -> copy from cursor position to end of the line
y^ -> copy from cursor position to beginning of the line
p -> put after cursor
P -> put before cursor

Note:
delete & yank go into vi's buffers & the buffer holds only the most recent yank/delete
As with delete, y can use a number or movement command


Searching text:

/ -> search for a pattern

Using regex in search patterns:

. -> a search for a.c yields abc or aec i.e. the . (dot) replaces exactly one character.
\ -> the backslash is used to remove special meaning of special characters like ., $ & ^
^string -> search for lines beginning with the searched string.
$string -> search for lines ending with the searched string.
[] -> matches a character set. The expression in the brackets stands for a single character in the set.


Search & replace:

:%s/old/new/g -> replaces every occurance of old with new in the entire file.
:%s/the[ym]/(&)/g -> enclose the search results in parenthesis throughout the file.
:%s/\(he\) \(is\)/\2 \1/ -> replace all occurances of 'he is' with 'is he'.

Indenting:

>> -> incdents current line (inserts a tab)
<< -> outdents current line (removes a tab)

Note:
Both >> & << can use a number prefix to indent/outdent multiple lines.


Filtering through shell commands:

!! ->  filters current line through shell command
n!! -> filters n lines
!% -> filters to matching pattern
!{ -> filters previous paragraph
!} -> filters next paragraph

Although this is a cheat sheet but I feel the need to elaborate on filtering. Vi allows the usage to any shell command that accepts some type of text as input, manipulate the text & provide output.
This way we can use the text manipulation capabilities of awk, sed & tr from within vi.

Using lines & line ranges in colon commands:

: line [,line] command -> performs commands on lines specified.
n -> line number
. -> current line
$ -> last line of file
/regex/ -> regular expression
% -. all lines.


Here are a couple of examples:

:%>> -> indent all lines.
:.,$ ! tr a-z A-Z -> change all lines between current line & last line of the file to upper case.
: /the/, /end/ d -> delete everything between the strings 'the' & 'end'

Using capture groups in grep in Linux

Introduction Let me start by saying that this article isn't about capture groups in grep per se. What we are going to do here with gr...