From RootdevWiki
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