If you need to access your machine remotely and have a dynamic public IP (like me), you may find this system handy. We're going to write a script which determines your IP and emails it to you every day via a cronjob. For simplicity we're going to use GMail's servers to send the email, so you'll need a GMail account, even if it's just a throwaway for this purpose alone.

First let's install a handy script called sendEmail and an additional library for connecting to SSL-enabled servers via perl.

sudo apt-get install sendEmail libio-socket-ssl-perl

Next we're going to create a script which determines your public IP, and then emails it to you in send_my_ip.sh:

#!/bin/bash
IP=`exec wget -q -O - checkip.dyndns.org`
sendemail -s smtp.gmail.com -t wheretosendyourip@server.com -f youraccount@gmail.com -m $IP -xu youraccount@gmail.com -xp yourgmailpassword -o tls=auto

What a mess! Let's take it line by line. The first line is your standard shebang with the path to bash. On the next line we're calling wget to grab the html of http://checkip.dyndns.org and storing it in a variable called IP. On the next line we're calling sendemail (notice the lower case e in the program call), and specifying some arguments including the email address you want to send the IP to, and the account details of the account you're sending it from. These addresses can be the same, as we're just using a GMail account because they're free and it avoids the hassle of setting up a local email server.

Next let's make this script executable:

chmod +x send_my_ip.sh

At this point you can test your script by running it directly from the command line with

./send_my_ip.sh

Finally, we need to create a cronjob which automatically calls this script every day to make sure we always have the current public IP. To edit your cron file run:

crontab -e

If this is your first time editing your cron file, it will prompt you for your editor of choice. I prefer vim, but if you're not familiar with vim, choose nano. I want to run this script which is in my home directory every day a few hours before my day starts. Enter the following on a new line at the bottom of the file:

0 5 * * * ~/send_my_ip.sh

Save and exit the file and that's it. Cron will run the script at the times you set it. There is a ton of information out there on defining cronjobs, so I'll leave it as homework to setup different email schedules.

Once you really get used to using vim, you start wanting everything to work like it. Fortunately there is an easy way to enable vim bindings in your terminal.

set -o vi

To make this change permanent, you can add it to your .bashrc (or .bash_profile) with:

echo "set -o vi" >> ~/.bashrc

This change will enable insert and normal mode in bash. Opening a new bash terminal window will place you in insert mode as you'd expect, and you can hit ESC or CTRL-[ to go to normal mode for all of that vim goodness you're so hooked on. Enjoy!

In search of a more minimalistic bash prompt, I ran across this great one-liner for creating a fish-esque prompt for bash. This prompt only displays the first letter of each directory above your current one, and the full name of the current directory. For example, if I were in:

~/projects/conjurecon/httpdocs/images

it would display:

~/p/c/h/images$

Give it a try, you may like it. Just add the following lines to ~/.bashrc (or ~/.bash_profile). To get your old prompt back just remove the two lines. In either case, you'll have to reload your terminal to see changes to your prompt. Enjoy!

PROMPT_COMMAND='CurDir=`pwd|sed -e "s!$HOME!~!"|sed -re "s!([^/])[^/]+/!\1/!g"`'
PS1="\$CurDir\$ "

I couldn't find the original author of this nice little one-liner. If someone else can, I'd love to link back to the original.

Update for OSX users: If you're trying to get this working on OSX you need to make one small adjustment. The flag for extended regex in sed for OSX is -E and not -r like above, so you can accomplish the same thing like so:

PROMPT_COMMAND='CurDir=`pwd|sed -e "s!$HOME!~!"|sed -Ee "s!([^/])[^/]+/!\1/!g"`'
PS1="\$CurDir\$ "

Enabling auto-complete in the interactive python interpreter will greatly increase your development speed. Sometimes you can't recall a method's name or you're not sure which method to use in the first place.

First we're going to create a file in your home directory called ".pythonrc" which will hold our configuration details. This file should contain the following:

import rlcompleter, readline
readline.parse_and_bind('tab:complete')

Then we'll set the PYTHONSTARTUP environment variable in our .bashrc (or .bash_profile if you're using that). If the PYTHONSTARTUP variable is set to a readable file, then the contents of that file will be run before anything else when the interactive interpreter is run.

echo "export PYTHONSTARTUP=~/.pythonrc" >> .bashrc

Then either open a new terminal window or reload your .bashrc file:

source ~/.bashrc

You're all set, just run python to enter the interpreter and give it a whirl. For example, run:

import sys

Then type in "sys." and hit tab twice, and you'll see all the methods on the sys object.

If you've been following along since Python Environment for Ubuntu: Part 1, you should now have virtualenv (with virtualenvwrapper) and pip installed, ready to be used.

You'll want to create a virtual environment for each of your projects. For example, if I were creating a environment for conjurecode, I might run:

mkvirtualenv conjurecode

It will run through some preliminary installs (including distribute or setuptools), create some hooks that we will take a look at later, and activate your newly created environment. You'll notice that your prompt has now changed to include the name of your environment in parenthesis. This is to notify you that you are currently working in the listed virtualenv. Any python scripts which you run from inside this virtualenv will only have access to these installed packages. To illustrate this somewhat, let's jump into the interactive python interpreter and look at our python path. Then we'll deactivate our virtualenv to return to our normal environment and look at it again.

To enter the interpreter, simply run, after which you will be greeted by a >> prompt:

python

To view our python path, we'll execute the following:

import sys
sys.path

You should see a lot of references to your home directory (such as /home/[your_username]/.virtualenvs) in your python path at this point. Since we are in our virtualenvironment, python knows to use only packages from the virtualenv path. To exit the python interpreter:

exit()

Next let's deactivate our virtualenv and return to our normal environment, simply by entering the following at the command prompt:

deactivate

You should see that you've returned to your normal prompt, indicating that you are no longer in any virtualenv. If you were to run the interactive python interpreter again at this point, you would see references to /usr/local/lib or something similar indicating that python is now using your system wide packages.

When you first created your virtualenv it was automatically activated for you, but once you've deactivated it, you'll need to manually activate it once you're ready to work on your project again. We do this with the workon command and the name of your project. When using workon, it will helpfully autocomplete your virtualenv project names with TAB.

workon conjurecode

If you need to remove a virtualenv, you can use the command rmvirtualenv and provide the name of the environment you'd like to remove. Make sure that the environment you're trying to remove isn't currently active and then issue the command:

rmvirtualenv conjurecode

You should now know how to create, activate, disable and remove virtual environments and have some idea of the way they control which packages your python scripts have access to. Next I'm going to review some basics of using pip to manage packages for each of your virtualenvs.

We're going to go through a few steps to get a nice development environment for working with Python (and Django) on Ubuntu.

We're going to be using pip to install and manage packages, but first we need easy_install, which comes with the setuptools package. To install setuptools (and easy_install), run the following:

sudo apt-get install python-setuptools

To ensure this has worked, run the following command which should return the version number of easy_install.

easy_install --version

To install pip run:

sudo easy_install pip

Again to verify that pip was installed correctly, check its version.

pip --version

Next we'll see pip to install virtualenv and virtuenvwrapper:

sudo pip install virtualenv
sudo pip install virtualenvwrapper

Next, we're going to set virtualenv to store our virtual environments in our home folder to keep things tidy:

mkdir ~/.virtualenvs
echo "export WORKON_HOME=~/.virtualenvs" >> ~/.bashrc

Setup bash to work with virtualenv (this should be the path to your virtualenvwrapper.sh):

echo "source /usr/local/bin/virtualenvwrapper.sh" >> ~/.bashrc
echo "export PIP_VIRTUALENV_BASE=~/.virtualenvs" >> ~/.bashrc

Finally, one more recommended step. We're creating an alias which will cause mkvirtualenv to not use site packages and to use distribute (instead of setuptools).

echo "alias mkvirtualenv='mkvirtualenv --no-site-packages --distribute'" >> ~/.bashrc

To reload our new bash settings without restarting our shell, run the following (or just open a new terminal window), otherwise you will get 'command not found' errors when running virtualenv:

source ~/.bashrc

That's it! You can now begin creating and using virtual environments in Part 2.

In order to have MySQL support for python, you must install the MySQLdb package. This can easily be done with pip, but first we'll need to install mysql_config and python-dev (if you haven't already):

sudo apt-get install python-dev
sudo apt-get install libmysqlclient-dev

Then, if you have pip installed, enter into your virtualenv if you're using one, and install via pip like so:

pip install MySQL-python

If you need to monitor the contents of a file while you work, especially one that changes often, like a log file for instance, use the tail command. Tail will display the end of a file, and the -f flag will output additional data as it is added to the file. This is an ideal way to monitor your apache log files for example (your error log path may vary):

tail -f /var/log/apache2/error.log

If I'm working in an environment where error reporting is disabled for some reason, or I otherwise need to monitor the contents of a log file, I typically leave this command running in a small terminal window.

Check out the man page for tail to control how many lines are outputted at once with the command 'man tail', or view the man page online.

Sometimes you may want to find a string which is in a particular file, or in a file which is in a particular directory. If you were looking for the word 'foo' in filename.txt, you would use the command:

grep 'foo' filename.txt

If you want to see what line foo occurs on in filename.txt, you would use the -n flag like so:

grep -n 'foo' filename.txt

If you want to search an entire directory of files for a specific string, you would provide a directory instead of a filename, again using the -n flag if you would like to know the line numbers which foo occurs on. In this case, grep will return the file(s) it finds the string in.

grep 'foo' ./*

If you want to search the current directory and all directories below it, use the -r flag.

grep -r 'foo' ./

Grep is an incredibly powerful tool, so you should try revisiting its man page periodically to pickup on new uses for it. In fact, why don't you view the man page online right now.

To replace the text "foo" with the text "bar" in filename.txt from the command line, you would use the following command:

sed -i 's/foo/bar/g' filename.txt

The "-i" flag is for interactive mode, which will makes changes to the file you provide. If you want to preserve the original file, you can run the command without the -i flag and instead provide an output file, like so:

sed 's/foo/bar/g' filename.txt >> output.txt

For more information on the sed command, run 'man sed', or view the man page online.