Thursday, March 26, 2009

Grouping users of same group - awk bash


This is a sample /etc/passwd file:

$ cat passWD
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:2:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:2:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
news:x:9:12:news:/etc/news:

In the above file, we need to group the users(1st field) which belong to the same group (4th field)

Solution1:

$ awk -F ":" 'END { for (i in Arr) print i FS Arr[i] }
{ Arr[$4] = Arr[$4] ? Arr[$4] FS $1 : $1 }' passWD

Output:
7:lp
12:mail:news
0:root:sync:shutdown
1:bin
2:daemon:adm:halt


Solution2:

$ awk -F ":" '{
Arr[$4]=sprintf("%s:%s",Arr[$4],$1)}
END {for ( i in Arr) {printf("%s%s\n",i,Arr[i])}}
' passWD

Output:
7:lp
12:mail:news
0:root:sync:shutdown
1:bin
2:daemon:adm:halt

Tuesday, March 17, 2009

Changing temporary directory for sort - bash

I was sorting a very big file using Linux sort command and unfortunately the sort failed as there was not enough space on my /tmp directory.

$ sort -t "|" -k5 ka.log.32323112.out > ka.log.32323112.out
sort: /tmp/sort1928700448: write error: No space left on device

just to mention, sort by default uses /tmp for temporaries.

So, how you can tell sort to use some other directory for temporaries ?

From man pages of sort(1)

-T, --temporary-directory=DIR
use DIR for temporaries, not $TMPDIR or /tmp; multiple options specify multiple directories

$ sort -T /home/jadu/ -t "|" -k5 ka.log.32323112.out > ka.log.32323112.out

It worked :-)

Another way would be : export env variable TMPDIR to some directory which have sufficient space.

e.g.

$ export TMPDIR=/path/to/other/directory
$ sort -t "|" -k5 ka.log.32323112.out > ka.log.32323112.out

It worked too :-)

Monday, March 16, 2009

Temporarily disable an alias - bash shell

Listing the configured aliases on my box.

$ alias
alias mc='. /usr/share/mc/bin/mc-wrapper.sh'
alias rm='rm -i'

As you can see, rm is aliased as 'rm -i' (i.e. prompt before every removal)

So if you try to remove any file using 'rm', its going to prompt you for confirmation.

$ rm file.txt
rm: remove regular empty file `file.txt'? y

Now if you want the use 'rm' command without the alias additions (rm -i), you have two ways:

Way 1:
Unaliasing a command by simply prefixing the command with a \

$ \rm file.txt

Way2:
Other alternative: Using unalias command

$ unalias rm

The above 'rm' one is just an example to illustrate this, (you can also do 'rm -f' for the same :-))

Tuesday, March 10, 2009

Highlight match with color in grep command

Like bash ls command, grep supports color in its output. i.e. you can highlight the text that grep matches with color.

This is controlled by "--color" option with grep command which basically surround the matching string with the marker find in GREP_COLOR environment variable.

$ grep --color=auto <pattern> <file>

Grep's default highlight color is red (shown below in the snap).



You can change this color by setting the GREP_COLOR environment variable to different combinations (from the color code list given below).

I use

$ export GREP_COLOR='1;30;43'

which basically highlights the matched pattern with foreground color black and background color yellow (shown below in the snap).



The set display attributes list:

0 Reset all attributes
1 Bright
2 Dim
4 Underscore
5 Blink
7 Reverse
8 Hidden

Foreground Colours
30 Black
31 Red
32 Green
33 Yellow
34 Blue
35 Magenta
36 Cyan
37 White

Background Colours
40 Black
41 Red
42 Green
43 Yellow
44 Blue
45 Magenta
46 Cyan
47 White

Related post:
- Bash ls command color support
- Colorful man pages in ubuntu

Sunday, March 8, 2009

Repeat a character in bash scripting

Requirement: Repeat a particular character n number of times and print in a single line.

e.g. Repeat the character '+' 10 times and print the output in a single line.

The solutions:

#Using bash for loop:
$ for((i=1;i<=10;i++));do printf "%s" "+";done;printf "\n"
++++++++++

$ for i in $(seq 10); do echo -n '+'; done
++++++++++

$ for i in {1..10};do printf "%s" "+";done;printf "\n"
++++++++++

#Using bash seq:
$ seq -s "+" 11 | sed 's/[0-9]//g'
++++++++++

#Perl one liner for the same:
$ perl -e 'print "+" x 10,"\n"'
++++++++++

#And using bash printf:
$ printf -v f "%10s" ; printf "%s\n" "${f// /+}"
++++++++++

Thursday, March 5, 2009

Print text in style box - bash scripting

The script:


#/bin/bash

_Box () {
str="$@"
len=$((${#str}+4))
for i in $(seq $len); do echo -n '*'; done;
echo; echo "* "$str" *";
for i in $(seq $len); do echo -n '*'; done;
echo
}

_Box "Welcome to AUDIT menu"


Execute the script:

$ ./box.sh
*************************
* Welcome to AUDIT menu *
*************************


Some points on the above script:

a) In the script, _Box is a function for generating style box. Any text sent as its argument will be shown within a stylish text box (as we saw above)

b) $@ : List of all shell arguments (here arguments to the function _Box)

c) len variable will be assigned to length of the string(argument)+4. Read how we can find string length in bash here

d) The for loops will print "len" number of * (read about seq)

e) -n option with echo (-n: do not output the trailing newline)

Related post:
- Generate a chess board pattern in bash scripting

Test for empty directory - bash scripting

Lets see how we can check whether a directory is empty or not in bash scripting.

#Create a directory
$ mkdir testdir

#Usual way to check if a directory is empty or not
$ [ -z $(ls testdir/) ] && echo "empty" || echo "NOT"
empty

#Lets create a file in testdir
$ touch testdir/file1

#Oh, it works, great
$ [ -z $(ls testdir/) ] && echo "empty" || echo "NOT"
NOT

#Create one more file, file2
$ touch testdir/file2

#Now see, ohh!!! it has faced some problem
$ [ -z $(ls testdir/) ] && echo "empty" || echo "NOT"
-bash: [: file1: binary operator expected
NOT

#Solution to the above:
$ [ -z "$(ls testdir/)" ] && echo "empty" || echo "NOT"
NOT

#Clear the testdir
$ rm testdir/file*

#So that
$ [ -z "$(ls testdir/)" ] && echo "empty" || echo "NOT"
empty

#Create a hidden file in the testdir
$ touch testdir/.hden

#But the above test condition is not going to take account of hidden files (as we are doing only ls)
$ [ -z "$(ls testdir/)" ] && echo "empty" || echo "NOT"
empty

#So use -A (do not list implied . and ..) option with ls
$ [ -z "$(ls -A testdir/)" ] && echo "empty" || echo "NOT"
NOT

#Create a file
$ touch testdir/file1

#Working ...
$ [ -z "$(ls -A testdir/)" ] && echo "empty" || echo "NOT"
NOT

#Remove the files (including hidden file) from testdir
$ rm testdir/.hden ; rm testdir/file1

#So the above is working.
$ [ -z "$(ls -A testdir/)" ] && echo "empty" || echo "NOT"
empty

But if we use -a option instead of -A
$ [ -z "$(ls -a testdir/)" ] && echo "empty" || echo "NOT"
NOT

This is because:

$ ls -a testdir/
. ..

But
$ ls -A testdir/

-A do not list implied . and ..

If you have any other way, feel free to post a comment. Thanks

Tuesday, March 3, 2009

Concatenate only digits from string - bash tr

Just to introduce a good use of Linux tr command; if you need to concatenate the digits from a string, here is a way:

$ echo "Abc123d56E" | tr -cd '[[:digit:]]'
Output:
12356

From tr man pages:

SYNOPSIS

tr [OPTION]... SET1 [SET2]

-c, -C, --complement: first complement SET1
-d, --delete : delete characters in SET1, do not translate

Similarly:

$ echo "Abc123d56E" | tr -d '[[:digit:]]'
Output:
AbcdE

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