From RootdevWiki

Jump to: navigation, search

Bash links

Contents

Tips and Tricks

Timestamps in Bash History

Ever wished your bash history files had timestamps so you could see exactly when someone deleted that crucial config file or stopped that apache process?

Just add the following to your .bashrc and Bob's your father's brother:

HISTTIMEFORMAT="%F %T"

Arithmetic

Arithmetic Expansion

It is possible to do fixed width integer arithmetic just using bash arithmetic expansion, which is fine for simple tasks but be warned there is no allowance for overflow, as follows:

$((2+2))

So:

~$ echo $((2+2))
4

That's all there is to it. Alternatively, use one of the handy utilities such as bc

bc

[foo@localhost ~]$ bc -q
2^8
256

1+3
4

sqrt(9)
3

and piping...

echo "20 * 5" | bc

Loops

For Loops

copy test1.html to testN.html

for ((i=1;i<11;i++));do echo $i ; cp test1.html test$i.html ; done

Use find inside a loop to perform inplace edit

for i in `find ./* -name '*.html'` ; do echo $i ; ls -al $i ; done 

Remove every second line from a file

for i in *.html ; do echo $i ; perl -ni -e '$.%2?print:();' $i ; done
  or 2 chars less for the golfers out there...
for i in *.html ; do echo $i ; perl -ni -e 'print if$.%2' $i ; done

Note: $. is the current line count; -ni performs an inplace edit inside a virtual while block

Loop the Loop

Count the number of hits on files in a directory and (roughly) work out the data transfer.

In this example we are looking for media files (.mpg & .wmv) in:

/var/www/foo/htdocs/downloads/files/

for i in `ls |egrep -v gif\|pdf`; do echo "File: $i"; \
for j in `grep $i /var/log/apache/foo/access_log |wc -l`; \
do echo "Count: $j"; for k in `du $i |cut -f1`; \
do for l in `echo "scale=2; $k / 1024" | bc`; \
do echo "Size: `echo "$l * $j"|bc`Mb"; \
done; done; done; done

Behold The Power of Awk

How to do the same as the loops of fury above but actually get an accurate reading of the amount of data transferred rather than multiplying the amount of hits by the file size:

LOG="/var/log/apache/foo/access_log"; \
for i in `ls |egrep -v pdf\|gif`; do \
echo "File: $i"; grep $i $LOG|awk '$10 !~ /-/ { a[x]+=$10 } \
END { print "Size: " a[x]/1024000"Mb" "\n" "Count: " NR "\n"}'; \
done

Or you could....

Behold The Power of Perl

Contributed alternative to the above loop:

perl -ne '$x+=$1if(/$r/)}BEGIN{$r=qr/\"\s\d\d\d\s(\d+)\s\"/}END \
{print$x/1024000' access_log

NB This does not do the same as the awk command above, it discards any line with a '-' in it, not just if there is a '-' in the data transferred field. CD.

Infinite Loops

How to put bash into an infinite loop on the command line:

while : ; do ...

Or if you can't remember that somewhat obscure syntax:

while yes; do.....

Or even:

while false; do ....

Putting this to use: say you are logging a process and are concerned your log file could very quickly get out of hand, you could start a loop to report the size of the log file every 60 seconds:

while : ; do du -h messages; sleep 60; done

(or alternatively, you could use the watch command which does exactly this)

Cut

Cut example

for i in tomcat* ; do echo $i ; grep "Host name=" $i/conf/server.xml \ 
| cut -d'"' -f 2 ; done

See Also