Grep: The single most useful command of Linux.

I love Linux. Why? Because it has so many cool cool cool … commands like grep, sed, find, etc. Of all the commands, I use grep the most. If grep is taken out of Linux then I will be severely crippled. Almost everyday I need to use it.

I will give you a recent case where I fixed a bug in LinuxDCpp in just 15 mins even when I had never looked into its code before and I had absolutely no experience building GUI applications in C++ or using GTK libraries.

I am using LinuxDCpp 1.0.1 which has a problem of not beeping when private messages are received even when I have configured it to do so. Because of this I had to repeatedly open the window of LinuxDCpp to check for new private messages. Then, one fine day I decided to fix this. The only problem was how and where. To answer my these questions I needed a starting point to start searching from. I had an idea; I realized that the best place to start searching from is the text – “Beep every time a private message is received“, this is the text that is displayed in the Preferences dialog of LinuxDCpp. I then un-tared the the source code of LinuxDCpp and opened the console in that directory, then I ran the command

$ grep -Rl "Beep every time a private message is received" .

Which yielded the result

./glade/settingsdialog.glade

I then opened that file and located the message. The code there read as following.

<child>
<widget class="GtkCheckButton" id="soundPMReceivedCheckButton">
        <property name="visible">True</property>
        <property name="can_focus">True</property>
        <property name="label" translatable="yes">
             Beep every time a private message is received</property>
        <property name="use_underline">True</property>
        <property name="draw_indicator">True</property>
</widget>
<packing>
        <property name="expand">False</property>
        <property name="fill">False</property>
</packing>
</child>


From my experience of HTML and common sense, I knew that soundPMReceivedCheckButton is the text that need to search for next. Hence I ran the command

$ grep -Rl "soundPMReceivedCheckButton" .

Which yielded the output

./linux/settingsdialog.cc
./glade/settingsdialog.glade

The second line was expected, but the first line contained the destination I must head to next. The code in that file read

// Sounds
sm->set(SettingsManager::PRIVATE_MESSAGE_BEEP, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(getWidget(
  "soundPMReceivedCheckButton"))));
sm->set(SettingsManager::PRIVATE_MESSAGE_BEEP_OPEN, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
  getWidget("soundPMWindowCheckButton"))));

From here on knowledge of C++ was required, but still grep was helpful. The lines spoke to me that there is a an object ‘sm’ which has a method ‘set’ which allows to set the properties of the program. PRIVATE_MESSAGE_BEEP is a constant which means that LinuxDCpp must beep on receiving the private message. From common sense, I concluded that the part of the program which actually generated the beep too must check for whether the property is SettingsManager::PRIVATE_MESSAGE_BEEP or not; in other words, that part of the program too must have the text PRIVATE_MESSAGE_BEEP. Hence my next command

$ grep -Rl "PRIVATE_MESSAGE_BEEP" .

I got the following outputs.

./client/SettingsManager.cpp
./client/SettingsManager.h
./linux/settingsdialog.cc
./linux/privatemessage.cc

As we already have seen the definition SettingsManager::PRIVATE_MESSAGE_BEEP, which clearly meant that PRIVATE_MESSAGE_BEEP must have been defined in the file SettingsManager.h. The only interesting result among them is privatemessage.cc. There I at last found what I was looking for. The code read

if (BOOLSETTING(PRIVATE_MESSAGE_BEEP_OPEN))
  gdk_beep();

In that very file the searched for gdk_beep() which took me to the code

if ((state & GDK_WINDOW_STATE_ICONIFIED) || mw->currentPage_gui() != getContainer())
  gdk_beep();

This is the code which was actually triggered on receiving private message and the code above that is activated when the private message window is opened.

The clear culprit was gdk_beep(). From Goggling out I found that it is part of GTK/GDK library and it is supposed to produce a beep from the internal speaker of the computer, but as per the many posts I saw on the various forums, it usually didn’t work. The only solution was to replace that with some other code. The easiest I could think of was using an external command to play a sound file. I opted for aplay which is usually installed on all current Linux computers. Also, I coded it such that user can configure LinuxDCpp to use any other commands by setting LINUX_DCPP_SND environment variable to the command to execute on receiving private message. For that I replaced

if (BOOLSETTING(PRIVATE_MESSAGE_BEEP_OPEN))
  gdk_beep();

with

if (BOOLSETTING(PRIVATE_MESSAGE_BEEP_OPEN))
{
//Added by AppleGrew
const char *sndCmd = getenv("LINUX_DCPP_SND");
if(!sndCmd) {
        string cmd = "aplay \"/usr/local/linuxdcpp/ping.wav\"";
        system(cmd.data());
}else{
        system(sndCmd);
}

I then edited the SConstruct file to automate the copying of the ping.wav file. For that added th following codes.

snd_file = ['ping.wav']
env.Alias('install', env.Install(dir = env['FAKE_ROOT'] + env['PREFIX'] + '/share/linuxdcpp', source = snd_file))

But, there was still a big problem. The SConstruct allowed the user to install it in /usr directory (the default is /usr/local). That meant I somehow needed to find out during runtime the location of the files. LinuxDCpp was already able to locate its pixmap (graphics) files, which are stored in the location – prefix_loc/pixmaps (prefix_loc is either /usr or /usr/local), I just needed to locate that code. It was clear that whatever mechanism LinuxDCpp was using, it will undoubtedly return the location /usr or /usr/local, and hence the code that accessed the pixmap files then would have to create the pixmap location as

string pixmap_location = function_or_method_that_gives_the_prefix_location + "/pixmaps"

Hence I ‘grepped’ for pixmaps.

$ grep -Rl "pixmaps" .

Which yielded

./Changelog.txt
./Readme.txt
./linux/hub.cc
./linux/mainwindow.cc
./SConstruct

And then and there I found what I was seeking.

// Load icons. We need to do this in the code and not in the .glade file,
// otherwise we won't always find the images.
string file, path = WulforManager::get()->getPath() + "/pixmaps/";

WulforManager::get()->getPath() was the method I needed. Now the new code in privatemessage.cc read

if (BOOLSETTING(PRIVATE_MESSAGE_BEEP_OPEN)){
//Added by AppleGrew
const char *sndCmd = getenv("LINUX_DCPP_SND");
if(!sndCmd) {
        string cmd = "aplay \"" + WulforManager::get()->getPath() + "/ping.wav\"";
        system(cmd.data());
}else{
        system(sndCmd);
}[/code]

This was it. Nice and smooth. I still don't know anything about WulforManager or SettingsManager declarations or the GTK libraries, yet I could finish this up fast and smoothly. All thanks to grep!

Find the number of lines of code your project has.

After completing a big and satisfying project you may want to collect various stats about your project. One of them is the total number of lines of code your project has. As with all big projects it will probably have large number of files tucked into various directories and sub-directories and sub-sub-directories,…. you get the idea; this is very tedious to do manually.

In Linux you have a cool trick to do just that! Run the following in the directory with contains your source code.

find . -type f -exec cat ‘{}’ \;|wc -l

If the directory also contains files other than the source code, e.g. .class files along with .java files, then you can ask find to choose files with a particular pattern using the following command

find . -type f -iname “*.java” -exec cat ‘{}’ \;|wc -l

The above command will choose only .java files.

magic_shutdown: Shutdown computer remotely using Magic Packet

The title says it all. If you don’t know what a Magic Packet is then read here. Below is the code of a shell script (I call magic_shutdown) that uses tcpdump to listen for Magic Packets. When it receives on then the shell script verifies its content to make sure that this packet was meant for this computer. Note this script doesn’t require that your network interface card support Wake-on-LAN. It has no special hardware dependencies.

All-in-all, this script lets you create create a shortcut which will act as remote power button for your computer. Press it to turn the computer ON. Press it again to turn the computer OFF.

Get magic_shutdown‘s code
License: GNU Public License version 3.

[code lang=”bash”]#!/bin/bash
#Author:AppleGrew
#License:GPL version 3

listenPort=9
interface="eth0"

#Forking to daemonize…
if [[ "$2" != "forked" ]]
then
echo "Forking $0…"
"$0" "$1" forked &
echo "Forked."
exit 0
fi

#Creating pid file
ppid=$$
echo $ppid >"$1"

echo "Started"
mac=`ifconfig "$interface"|head -n1|sed -e ‘s/.*HWaddr \([0-9:a-fA-F]*\)/\1/g’ -e ‘s/://g’`
pckt_expect=`echo "ff ff ff ff ff ff $mac $mac $mac $mac $mac $mac $mac $mac"|sed ‘s/ //g’|tr ‘A-Z’ ‘a-z’`
while `true`
do
pckt_data=`tcpdump -i "$interface" -x -c 1 udp port ${listenPort}`
if [[ $? != 0 ]]
then
echo "tcpdump returned error."
exit 1
fi

pckt_data=`echo "$pckt_data" | \
grep ‘0x[0-9]*:’| \
tr ‘A-Z’ ‘a-z’| \
sed ‘s/[ \t]//g’| \
sed ‘s/0x[0-9]*:\([0-9a-f]*\)/\1/g’| \
tr -d ‘\n\r’| \
cut -c 57-`
if [[ "$pckt_data" == "$pckt_expect" ]]
then
echo "Matched! Received Magic packet shutting down…"
shutdown -P now #Not recommended
#For Gnome #Doesn’t work dunno why?
#dbus-send –session –dest=org.gnome.PowerManager \
# –type=method_call –print-reply –reply-timeout=2000 \
# /org/gnome/PowerManager org.gnome.PowerManager.Shutdown
#For KDE 3.5
#dcop `dcop|grep power-manager` power-manager shutdown
exit 0
fi
done

echo "EXITED"
exit 0[/code]

Below is the startup script that must be used to launch magic_shutdown script.

Get launch_magic_shutdown‘s code
License: GNU Public License version 3.

[code lang=”bash”]#!/bin/bash
#Author:AppleGrew
#License:GPL version 3

SCRIPT="/opt/magic_shutdown"
PID_FILE="/var/run/magic_shutdown.pid"
case "$1" in
start)
test -f "$PID_FILE" && echo "Already Running…" && exit 1
"$SCRIPT" "$PID_FILE"
echo "Started"
;;
stop)
pid=`cat "$PID_FILE"`

tcpPid=`pgrep -P $pid tcpdump`
kill -9 $pid
kill -2 $tcpPid
if [ -f "$PID_FILE" ] && ! ps -p $pid >/dev/null
then
rm -f "$PID_FILE"
else
echo "Failed to delete pid file. Maybe its already deleted."
fi
echo "Stopped"
;;
esac[/code]

Installations:-
Assuming that you have downloaded the above two codes into your home directory. Now run the following commands.

sudo cp launch_magic_shutdown /etc/init.d
sudo chmod a+x /etc/init.d/launch_magic_shutdown
cd /etc/rc2.d
sudo ln -s ../init.d/launch_magic_shutdown S99launch_magic_shutdown

sudo cp magic_shutdown /opt/magic_shutdown
sudo chmod a+x /opt/magic_shutdown

Hope this helps. Report in the comments section if you encounter any problem.


Update: Stuart’s Script
Stuart (see comment section) posted his version of magic_shutdown script. If the above one doesn’t work then maybe you should give this one a try.
[code lang=”bash”]#!/bin/sh
#Author: Stuart
#Original Author:AppleGrew
#License:GPL version 3

#Forking to daemonize…
if [[ "$2" != "forked" ]]
then
echo "Forking $0…"
"$0" "$1" forked &amp;
echo "Forked."
exit 0
fi

#Creating pid file
ppid=$$
echo $ppid &gt;"$1"

echo "Started"
interface=`route -n | grep "^0.0.0.0" | awk -F " " ‘{print $8}’`
mac=`ifconfig "$interface"|head -n1|sed -e ‘s/.*HWaddr \([0-9:a-fA-F]*\)/\1/g’ -e ‘s/://g’`
pckt_expect=`echo "$mac $mac $mac $mac $mac $mac $mac $mac $mac $mac $mac $mac $mac $mac $mac $mac"|sed ‘s/ //g’|tr ‘A-Z’ ‘a-z’`
while `true`
do
pckt_data=`tcpdump -i "$interface" -s 0 -x -c 1 \( \(ether dst "$mac" and not ip and not arp and not rarp\) or \(udp port 9\) \)`
if [[ $? != 0 ]]
then
echo "tcpdump returned error."
exit 1
fi
pckt_data=`echo "$pckt_data" | \
grep ‘0x[0-9]*:’| \
tr ‘A-Z’ ‘a-z’| \
sed ‘s/[ \t]//g’| \
sed ‘s/0x[0-9]*:\([0-9a-f]*\)/\1/g’| \
tr -d ‘\n\r’ | \
awk -F "ffffffffffff" ‘{print $2}’`
if [[ "$pckt_data" == "$pckt_expect" ]]
then
echo "Matched! Received Magic packet shutting down…"
rm -f $1
/sbin/poweroff
exit 0
fi
done

echo "EXITED"
exit 0[/code]

autoWallChange: Automatically changes wallpaper

About the script
This is a KDE (may not work in KDE 4) only shell script which changes wallpaper every few minutes as set by you. KDE too has a built-in feature to change wallpaper but it has few limitations:-

  1. It doesn’t show pictures within the sub-directories of the given path.
  2. It applies the same picture position setting (i.e. Scala&Crop, Tile, etc.) to all the pictures.

This script allows you to apply different picture position settings to pictures from different directories. e.g. if you use the following settings

picDir=”/home/geek/Pictures”
shapeDir=”Rectangle Square Tall”
shapeMode=”8 8 5″

Then pictures from /home/geek/Pictures/Rectangle and /home/geek/Pictures/Square will be shown using Scale & Crop position setting, and pictures from /home/geek/Pictures/Tall will be Titled Maxpect. Following is the table for which number stands for what position setting.

  • 1 -> Centered
  • 2 -> Titled
  • 3 -> Center Titled
  • 4 -> Centered Maxpect
  • 5 -> Titled Maxpect
  • 6 -> Scaled
  • 7 -> Centered Auto Fit
  • 8 -> Scale & Crop

This script is best used with my iflickrDown script (see here).

The code
License: GNU Public License version 3.

[code lang=”bash”]#!/bin/bash
#Coded by AppleGrew
#License: GPL version 3

#############################################
############Alternative way to set###########
##########the following variables############
#Create another shell script and export it #
#from there. #
#===============SAMPLE=======================
# #!/bin/bash
# export picDir="/home/geek/Pictures" #Donot put ‘/’ at the end
# export shapeDir="Square Rectangle Tall"
# export shapeMode="8 8 5"
# export changeWallIntv=2 #in mins
#
# ./autoWallChange >/tmp/autoWall.log & #Launching the main program.
############Configs##########################
picDir="" #Donot put ‘/’ at the end
shapeDir=""
shapeMode=""
changeWallIntv=1 #in mins
#############################################

tmpFile="/tmp/autoWallChange.tmp"
lstFile="/tmp/autoWallChange.lst"
fileLen=0
factor=0

shapeDir=( $shapeDir )
shapeMode=( $shapeMode )

echo "${shapeDir[@]}"
echo "${shapeMode[@]}"

function refreshFileList(){
local DIR_PATH=$1
local sM=$2
echo "Refreshing content of ‘$DIR_PATH’, shape mode is $sM"

if [ -a "$DIR_PATH" ] && [ -d "$DIR_PATH" ] && [ -w "$DIR_PATH" ]
then
for f in `find "$DIR_PATH" -type f -print | sed ‘s/ /|/g’`
do
matchFound=0
for fl in `cat "$tmpFile"`
do
fl=`echo "$fl"|sed -e ‘s/\([^>]*\)>\([^>]*\)/\1\n\2/g’|head -n 1|tail -n 1`
[[ "$fl" == "$f" ]] && matchFound=1 && break
done
[[ $matchFound == 0 ]] && printf "%s>%d\n" $f $sM >>"$tmpFile" && let ‘fileLen++’
done
let ‘factor=(fileLen-1)*100000000/32767’
fi
echo "Refreshed"
}

printf "">"$tmpFile" #Creating new empty file.
i=0
for shape in ${shapeDir[@]}
do
test -a "$picDir/$shape" && find -L "$picDir/$shape" -type f -print > "$lstFile.$i"
test -a "$picDir/$shape" && refreshFileList "$picDir/$shape" ${shapeMode[$i]}
let ‘i++’
done

shownPicsLine=0
lastL=""
totShown=0
RANDOM=$$
while true
do
let ‘l=(factor*RANDOM+100000000)/100000000’
test $totShown -ge $fileLen && lastL="" && totShown=0
while echo "$lastL" | grep -o "\"$l\"" > /dev/null
do
let "l++"
test $l -gt $fileLen && l=1
done
lastL="${lastL}\"$l\""
let "totShown++"

pfileL=`cat "$tmpFile"|head -n $l|tail -n 1`
pfilePath=`echo "$pfileL"|sed -e ‘s/\([^>]*\)>\([^>]*\)/\1\n\2/g’|head -n 1|tail -n 1|sed ‘s/|/ /g’`
pfileMode=`echo "$pfileL"|sed -e ‘s/\([^>]*\)>\([^>]*\)/\1\n\2/g’|head -n 2|tail -n 1`

if [ $totShown -ge $fileLen ]
then
lastL=""
totShown=0
fi

[ -f "$pfilePath" ] && dcop kdesktop KBackgroundIface setWallpaper "$pfilePath" "$pfileMode"

i=0
for shape in ${shapeDir[@]}
do
if test -a "$picDir/$shape" && ! find -L "$picDir/$shape" -type f -print | diff "$lstFile.$i" ->/dev/null
then
echo "’$picDir/$shape’ content changed"
refreshFileList "$picDir/$shape" ${shapeMode[$i]}
find -L "$picDir/$shape" -type f -print > "$lstFile.$i"
fi
let ‘i++’
done
echo "sleeping"
sleep "${changeWallIntv}m"
done<[/code]

Posting PHP codes on blog.

If you want to post PHP code on blog or any web page then its easy. Use the command:-

php -s /path/to/your/php/script > The_Code_to_post

This will generate a html code that you can directly paste in the web page’s code to display your code with syntax highlighting, but if you post this code in Blogger.com or Drupal then you will notice extraneous blank lines after every line of your code. This is due the fact that Blogger.com and Drupal insert a line break themselves whenever they encounter a new-line or carriage-return. To fix this problem, use the following command instead of the above one.

php -s /path/to/your/php/script | tr -d ‘\n\r’ > The_Code_to_post

Uploaded two projects on Sourceforge.net

A few days ago I uplaoded two projects on Sourceforge.net (world’s largest open source programs’ repository). They are LANSim and AG’s Library Manager.

LANSim

(Update: This has now been uploaded to Github – https://github.com/applegrew/lansim. Please download or fork it from there.)

This is a network simulator. This is meant to be user friendly as well as feature rich. This field lacks software with good user interface. Even the commercial softwares in this field is quite lame. This aimed to go along Multisim(R) and Blender(R) form.

URL:-

Homepage: lansim.sourceforge.net
SF site: sourceforge.net/projects/lansim

Developers:-

1) Rohit Singh
2) Dhiraj Prakrash
3) and me.

AG’s Libray Manager

This a versatile library manager made in Java. It requires MySql at backend to store the database. This is not made to function only as a library manager but can be used in many places like CD rental shops etc. It has the feature to export the result to Microsoft Excel format. It can also import from there (but there isn’t any easy way to do so currently). The number of fields of information you want to store for your items can be customised by changing the MySQL table structure (Currently there isn’t any easy way to do so).

Url:-

Homepage: libmanager.sourceforge.net
SF site: sourceforge.net/projects/libmanager

Developer:-

Me