Thursday, April 30, 2009

Using tabs in vim - short tutorial


With Vim 7.0, you can use tabs within vim. So now you can consolidate all your sessions into one window. Lets see some of the commands which will help you to explore the tab feature.

How to open a new tab in vim ?

:tabnew
:tabedit

:tabnew or :tabedit alone will open a new tab with empty buffer
:tabnew filename or tabedit filename will load the file in new tab

How to open files in separate tabs at start-up?

The following will open the 4 files in 4 separate tabs.

$ vim -p file1 file2 file3 file4

How to move between tabs ?

:tabnext (or :tabn)
:tabprevious (or :tabp)

or use gt in normal mode (Go to the next tab page. Wraps around from the last to the first one.)

:tabfirst (jump to the first tab)
:tablast (jump to the last tab)
:tabrewind

vim numbers the tabs from 0. So

:tabmove 2 (or :tabm 2)

will move to the 3rd tab.

Operation on all tabs ?
Now if you need to do a "search and replace" on all the tabbed files you have opened, tabdo will help you.
e.g. if you want to replace unit16 with unit32 in all the tabs

:tabdo %s/unit16/unit32/g

How to close tab(s)?

:tabclose (Close current tab page)
:tabonly (Close all other tab pages)

Help ?
For more on vim tab feature help

:help tab-page-intro

Also help page from vimdoc

Wednesday, April 29, 2009

Round off any epoch to day epoch in bash

Whats the present epoch now ?

$ date +%s
1240976848


Which is: GMT: Wed, 29 Apr 2009 03:47:28 GMT

Required: Round off the above epoch value to epoch corresponding to day epoch i.e. epoch corresponding to beginning of the day which is "Wed, 29 Apr 2009 00:00:00 GMT"

Here is the way:

$ echo - | awk '{print int(1240976848/86400)*86400}'
1240963200

Which is "GMT: Wed, 29 Apr 2009 00:00:00 GMT"

Lets have a file like this:

$ cat epochs.txt
a|1240976848|x
b|1240213332|y
c|1240112112|z
d|1240976549|a

Required: Round the 2nd field to the day epoch (beginning of the day epoch)

$ awk 'BEGIN {FS=OFS="|"}
{$2=(int($2/86400)*86400)} {print}
' epochs.txt

output:

a|1240963200|x
b|1240185600|y
c|1240099200|z
d|1240963200|a


** 86400 is the number of seconds in a day. (24*60*60)

Related post:
- Round off functionality using awk in bash
- Round off floats using awk sprintf function

Tuesday, April 28, 2009

Print lines from alternate files - awk

Input files:
$ cat file1
Mr A
Mr B
Mrs C
Mr D

$ cat file2
ID213
ID211
ID218
ID219

Required output:

ID213
Mr A
----
ID211
Mr B
----
ID218
Mrs C
----
ID219
Mr D
----


Awk solution:

$ awk '{print;getline < "file1";print $0 "\n----"}' file2


Python solution for the same:

file1 = open('file1', 'r')
file2 = open('file2', 'r')

for lineA in file1:
print lineA,
print file2.readline(),
print "----"


Related posts:
- Python readline example from my python newbie blog

Monday, April 27, 2009

Parsing env variable PATH in bash

Requirement: Check for the existence of the directories mentioned in PATH env variable.

The bash script:

#!/bin/sh
IFS=:

read dirs <<END
$PATH
END

for dir in $dirs
do
[ ! -e "$dir" ] && echo "$dir not exist" \
|| echo "$dir exist"
done

Executing the above bash script:

$ ./check-PATH.sh
/usr/local/bin exist
/usr/bin exist
/bin exist
/usr/X11R6/bin exist
/cygdrive/c/WINDOWS/system32 exist
/cygdrive/c/WINDOWS exist
/usr/bin exist
/usr/lib/sanity not exist


Read more about Bash IFS (Internal Field Separator) from tldp.org

Friday, April 17, 2009

Pull word under cursor - vim tip

Pull word under the cursor into a command line(ex mode) or search by pressing ctrl-r ctrl-w

This is very useful for yanking long values into substitutions or into search without using the mouse.

Another way of pulling the word under cursor to search (forward,backward)

"shift *" is equivalent to /\<word under cursor\> (forward search)
"shift #" is equivalent to ?\<word under cursor\> (backward search)

Tuesday, April 14, 2009

Find length of longest line - awk bash

This is how we can find the length of the longest line in a file.


$ awk ' { if ( length > L ) { L=length} }END{ print L}' file.txt

Output:
25


And also to print the longest line along with the length:


$ awk ' { if ( length > L ) { L=length ;s=$0 } }END{ print L,"\""s"\"" }' file.txt

Output:
25 "136068 sumAQSD.1236800000"


Read about awk built in string manipulation function length

Sunday, April 12, 2009

Sort and then diff two files - bash

e.g.

$ cat file1.dat
342
123
123
789
120

$ cat file2.dat
342
120
900
789
123
123

Now normal diff:

$ diff file1.dat file2.dat
1a2,4
> 120
> 900
> 789
4,5d6
< 789
< 120

Requirement: Sort both the files and take diff of the sorted outputs.

Normal approach would have been:

Way1:
$ sort file1.dat -o file1.dat.srt
$ sort file2.dat -o file2.dat.srt

And then, diffing the sorted output files.
$ diff file1.dat.srt file2.dat.srt
5a6
> 900

Way2:
Sort only one file. say

$ sort file2.dat -o file2.dat.srt

And then
$ sort file1.dat | diff - file2.dat.srt

Way 3: Using bash process substitution technique*
Other way of doing this without creating those temporary sorted files.

$ diff <(sort file1.dat) <(sort file2.dat)
5a6
> 900

* Bash process substitution:
Using this technique output of process (or processes) can be feed to stdin of another process (piping technique only allows stdout of one single command to another command stdin)

e.g.

$ diff <(command1) <(command2)
will show difference of command1 and command2 output.

More about bash process substitution can be read from here

Friday, April 10, 2009

Display file permission in octal - Linux stat

File permissions in Linux can be displayed in octal format using Linux stat command.

from man page of Linux stat(1) command

%A Access rights in human readable form
%a Access rights in octal
%n File name

$ stat -c '%A %a %n' *

One sample output:

-rwxr-xr-x 755 netp.sh
drwxr-xr-x 755 old_dump
-rw-r--r-- 644 tdiff.sh

Thursday, April 9, 2009

Replace field other than first occurrence in awk - bash

Graphically my requirement was something like this:

I had a csv file which looks like this:


I had to remove all the first fields other than the first occurrence of each unique first field.


This is how I achieved that.

Input file:
$ cat file.txt
3245,1239035917,560,0
3245,1239035919,560,0
3245,1239035947,460,0
3247,1239035967,60,0
3247,1239036917,560,0
3295,1239035917,70,0

Awk solution:

$ awk -F "," '!a[$1]++{print $0; next}{gsub ($1,""); print}' file.txt

Output:
3245,1239035917,560,0
,1239035919,560,0
,1239035947,460,0
3247,1239035967,60,0
,1239036917,560,0
3295,1239035917,70,0

Done.
Please put any more alternative in the comment section.

Monday, April 6, 2009

Sum with awk substr function - bash

I have already explained about awk substr function , using which a sub string can be extracted from a string.
Lets see how we can use substr along with a normal awk sum operation.

e.g. In the below file, lets try to sum all the numbers starting from character position 6 till position 10 for all lines except lines starting with T and Y.

$ cat file.txt
A052K2500sle12t09
K094T1200sle12t09
T129K1000@5900xpt
R5k9T1600tkxp90st
A152Y2700kle12t08
Yp90w1256newrt900

The awk solution:

$ awk '/^[^TY]/ { s+=substr($0,6,4) }
END { printf("sum=(%d)\n",s) }' file.txt

Output:
sum=(8000)

Related post:
- Print characters before and after a pattern using awk
- Sort date in ddmmyyyy format using awk
- Change date format using awk

Thursday, April 2, 2009

Split a file based on start pattern - awk

In one of my earlier post , I already discussed how we can divide a file like address.txt (below) into sub files, such that each of one contains only one address (in that example one address was being considered till the PIN number pattern)

$ cat address.txt
Mr X
Koramangala Post
3rd Cross, 17th Main
PIN: 12345
Mr Y
NGV
PIN: 45678
Mr Z
5th Ave, #23
NHM Post
LKV
PIN: 32456

Lets see how we can divide a similar file like address.txt into subfiles, each containing one address, but this time we will consider a address being starts from the pattern "Mr" or "Mrs" (i.e. All lines from "Mr" or "Mrs" till next "Mr" or "Mrs" should go to one file and so on)

I have just modified the file as

$ cat record.txt
Mrs X
Koramangala Post
3rd Cross, 17th Main
PIN: 12345
status=nill
Mr Y
NGV
PIN: 45678
Mrs Z
5th Ave, #23
NHM Post
LKV
PIN: 32456
spl case=yes

So we are expecting 3 subfiles like this:

$ cat add_1
Mrs X
Koramangala Post
3rd Cross, 17th Main
PIN: 12345
status=nill

$ cat add_2
Mr Y
NGV
PIN: 45678

$ cat add_3
Mrs Z
5th Ave, #23
NHM Post
LKV
PIN: 32456
spl case=yes

The solution:

$ awk '/^Mr|^Mrs/{close("add_"f);f++}{print $0 > "add_"f}' record.txt

Related post:
- Split file based on pattern using awk
- Sub dividing file using awk

Wednesday, April 1, 2009

Ctrl-s in Linux shell - vi hangs

It happened to me a lot many times. While working on Linux terminal, sometime my terminal hangs due to some key strokes that I make in hurry. Was not sure which key combination did the terminal to freeze. At last I found that. Thought of sharing here.

Pressing Ctrl-s inside vi editor or in Linux shell freezes the shell as it locks the terminal output.
We need to press Ctrl-q to resume the terminal output.

© Jadu Saikia http://unstableme.blogspot.com