Ever used grep and wanted to check that file with less? Now it is easy with wrapping functions, they parse grep outputted lines.
So lets say we search for info in rvm packages:
grep -rn '__rvm_use(' ~/.rvm/scripts
/home/mpapis/.rvm/scripts/selector:391:__rvm_use()
So now you want to see what is inside of ‘.rvm/scripts/selector’ at line 391
less -N +j391 /home/mpapis/.rvm/scripts/selector
But wouldn’t be nice to just write less, double click the found line and middle click:
less /home/mpapis/.rvm/scripts/selector:391:__rvm_use
This will work when using following function:
less()
{
local params=() param parsed
for param in "$@"
do
case $param in
(*:*)
parsed=( ${param//:/ } )
params+=( "-N" "+j${parsed[1]}" "${parsed[0]}" )
;;
(*)
params+=( "$param" )
;;
esac
done
command less "${params[@]}"
}
Put the above code into ~/.functions and source it in ~/.bashrc
test -s ~/.functions && . ~/.functions || true
Now restart your shell and enjoy you extended less function.
It has been long time since last post, but finally something useful shown up, today I want to present simple script for monitoring memory in Linux.
But first happy news: our server is now sucessfully migrated to nginx, no more apache, now maximal memory usage is 20MB per process.
So here is script, it is almost simple, find some processes, and kill them if to much RAM used:
#!/bin/bash
threshold_mb=25
kill_at_mb=$((threshold_mb*5))
memory=$(free -m | awk '{if (FNR==2) print $2}')
threshold=$((threshold_mb*100/memory))
kill_at=$((kill_at_mb*100/memory))
log=/dev/shm/psaux.log
count=$(ps aux | awk -v threshold=$threshold '{if (FNR==1 || $4>=threshold) print}' | tee $log | wc -l)
[ $count -gt 1 ] && echo "Showing processes over ${threshold_mb}MB, killing processes over ${kill_at_mb}MB" && cat $log
cat $log | awk -v kill_at=$kill_at '{if ($4>kill_at) print $2" "$4 }' | while read pid mem;
do
used_mb=$(($(echo $mem | sed 's/\.//')*memory/1000))
# fix rounding problem in awk
if [ $used_mb -gt $kill_at_mb ]; then
kill -9 $pid
echo "pid $pid used ${used_mb}MB - killed"
fi
done
rm -f $log
Most important in this script are first two variables, threshold_mb which is a limit for showing processes (it is rough comparison) and kill_at_mb which is limit for killing processes, by default this limit is 5 times bigger then showing threshold. Cause killing is more important operation additional check for used memory is more strict to be sure, only processes over the limit are killed.
Save it to disk and in crontab:
sudo crontab -e
add the following lines:
MAILTO=<your @email>
* * * * * /root/bin/psaux.sh
That’s all, now add some filter in your mailbox to ignore mails form server – this is all automatic, but you might want to have this for later check if some important processes are missing.
Doing some security check on my laptop I found that some files are kept on disk even I do not want to – /tmp directory
. Temp is kind of places in system that should not be kept on encrypted partition, so I have decided to use tmpfs
. First define an /etc/fstab
entry to keep /tmp
on tmpfs
:
tmpfs /tmp tmpfs rw,noexec,noatime,mode=1777 0 0
tmpfs /var/tmp tmpfs rw,noexec,noatime,mode=1777 0 0
Clean all data and mount it:
rm -rf /tmp/* /var/tmp/*
mount /tmp
mount /var/tmp
Now your data is kept only till yours computer is restarted. But wait it keeps growing, I restart my laptop once few months, what then? No problem a handy script might be useful, save it as /root/bin/clean_tmp.sh
:
#!/bin/bash
: old_minutes:${old_minutes:=60}
list_used()
{
lsof +D "$1" 2>/dev/null | awk 'NR>1{print $9}'
}
list_old()
{
find "$1" -type f -amin +$old_minutes 2>/dev/null
}
list_unused_old()
{
diff <(list_used "$1") <(list_old "$1") | awk '$1==">"{print $2}'
}
list_empty_dirs()
{
find "$1" -type d -empty
}
clean_all()
{
typeset _tmp_dir
for _tmp_dir in "$@"
do
list_unused_old "${_tmp_dir}" | xargs rm -fv
list_empty_dirs "${_tmp_dir}" | xargs rm -fvr
done
}
clean_all /tmp /var/tmp
What it does? – remove all files older then 60 minutes and not used by any application. Now connect script in root cron (sudo crontab -e
):
5 * * * * /root/bin/clean_tmp.sh
Now your temp is secure and clean. You will get list of removed files on your local mail account, to prevent this email remove just v
from xargs rm -fv
from the script.
Had you ever need of simple routing, like sharing your connection to other computer?
I had :) so here is a script which turns my laptop into a router, simple configuration, one command, to run it save the script as router.sh
#!/bin/bash
#configuration
IF_LOC=eth0
IP_LOC=192.168.67
IF_NET=wlan0
#script
IF_NET=$(ifconfig $IF_NET | awk ‘/inet/ {print $2}’ | grep -o ‘[0-9]*\.[0-9]*\.[0-9]*’)
#connect
iptables-save > /dev/shm/old_routes
ifconfig $IF_LOC inet $IP_LOC.1
ip route add $IP_LOC.0/24 dev $IF_LOC src $IP_LOC.1
iptables -t nat -A POSTROUTING -s $IF_NET.0/24 -j MASQUERADE
if ip route | grep $IP_LOC.1 >/dev/null
then
#message
clear
echo “Enter this information in connected machines:”
echo “IP address : $IP_LOC.2-254”
echo “Netmask : 255.255.255.0”
echo “Gateway : $IP_LOC.1”
echo “DNS : $(echo -n $(awk ‘/^nameserver/ {print $2}’ /etc/resolv.conf))”
echo “”
echo “Press ENTER to continue.”
read
#monitor connection
iftop -i $IF_LOC
else
echo “Error setting up network”
fi
#disconnect
ip route del $IP_LOC.0/24 dev $IF_LOC
ifconfig $IF_LOC down
iptables-restore < /dev/shm/old_routes
rm /dev/shm/old_routes
#end
[/sourcecode]
and give execute rights to the script:
[sourcecode lang="bash"]
chmod +x router.sh
[/sourcecode]
now just run it:
[sourcecode lang="bash"]
sudo ./router.sh
[/sourcecode]
Script will show configuration of new created network
[sourcecode lang="bash"]
Enter this information in connected machines:
IP address : 192.168.67.2-254
Netmask : 255.255.255.0
Gateway : 192.168.67.1
DNS : 217.172.224.160 89.228.6.21
Press ENTER to continue.
[/sourcecode]
and start monitor its traffic, to quit routing hit q or CTRL+C
It is simplest way to start sharing internet I know off
After long playing around with my prompt I finally made it stable and thought it’s time to share :)
So edit your ~/.bashrc file and add following lines on the end:
shopt -s promptvars dotglob histappend no_empty_cmd_completion cdspell xpg_echo
function parse_git_dirty {
echo -n $(git status 2>/dev/null | awk -v out=$1 -v std="dirty" '{ if ($0=="# Changes to be committed:") std = "uncommited"; last=$0 } END{ if(last!="" && last!="nothing to commit (working directory clean)") { if(out!="") print out; else print std } }')
}
function parse_git_branch {
echo -n $(git branch --no-color 2>/dev/null | awk -v out=$1 '/^*/ { if(out=="") print $2; else print out}')
}
function parse_git_remote {
echo -n $(git status 2>/dev/null | awk -v out=$1 '/# Your branch is / { if(out=="") print $5; else print out }')
}
export PS1='$(ppwd \l)\u@\h:\[33[33m\]\w\[33[0m\]$(parse_git_branch ":")\[33[36m\]$(parse_git_branch)\[33[0m\]$(parse_git_remote "(")\[33[35m\]$(parse_git_remote)\[33[0m\]$(parse_git_remote ")")\[33[0m\]$(parse_git_dirty "[")\[33[31m\]$(parse_git_dirty )\[33[0m\]$(parse_git_dirty "]")>'
I know it looks a bit complicated, unfortunately it is … this is wired bash rule that escape sequences are evaluated before evaluation of functions/variables evaluation.
Some examples of prompt using this script:
mpapis@papis:~/old_laptop/nicz-projects/content2:master> touch a
mpapis@papis:~/old_laptop/nicz-projects/content2:master[dirty]> git add .
mpapis@papis:~/old_laptop/nicz-projects/content2:master[uncommited]> git commit -m "added a file"
mpapis@papis:~/old_laptop/nicz-projects/content2:master(ahead)>git push origin master
mpapis@papis:~/old_laptop/nicz-projects/content2:master>
To make it more useful the prompt is also colored to distinguish between states of git repo.
For lazy users the script could be also replaced by very easy version, which prints git status before each prompt line (only where git is applicable):
export PS1='$(git status 2>/dev/null)\[33[0m\]\n$(ppwd \l)\u@\h:\[33[33m\]\w\[33[0m\]>'
Note: download the code from here http://niczsoft.com/files/2010/05/my-git-prompt.txt