Bash Script to Restore Tmux Session After Reboot

Listen to this Post. Powered by iSpeech.org

I first learned about Tmux from this SitePoint article. And it’s awesome. I don’t need to open 3-4 terminals anymore for my everyday work.

Anyway, what I’ll talk about here is a way to restore Tmux sessions after you reboot your computer. Actually, “restore” is the wrong word since as of now, you can’t store Tmux sessions (as of now). But, you can script it.

Here’s my take on the whole thing:

#!/bin/bash
#/home/ryann/scripts/restoretmux.sh
 
SESSIONNAME="work"
tmux has-session -t $SESSIONNAME $> /dev/null
 
if [ $? != 0 ]
	then
		# new session with name $SESSIONNAME and window 0 named "base"
		tmux new-session -s $SESSIONNAME -n base -d
		tmux split-window -t $SESSIONNAME:0 -h
 
		# new window for asterisk-billing project
		tmux new-window -t $SESSIONNAME:1 -n "asterisk-billing"
		tmux split-window -t $SESSIONNAME:1 -h
		# set directory for right pane
		tmux send-keys 'cd /home/ryann/projects/asterisk-billing/html/' 'C-m'
		# switch to left pane and set directory
		tmux select-pane -t $SESSIONNAME:1 -L
		tmux send-keys 'cd /home/ryann/projects/asterisk-billing/' 'C-m'
 
		## new window for processwire project
		tmux new-window -t $SESSIONNAME:2 -n "processwire"
		tmux split-window -t $SESSIONNAME:2 -h
		tmux send-keys 'cd /home/ryann/projects/processwire/build/processwire/' 'C-m'
		tmux select-pane -t $SESSIONNAME:2 -L
		tmux send-keys 'cd /home/ryann/projects/processwire/build/' 'C-m'
 
		## switch the "base" window
		tmux select-window -t $SESSIONNAME:0
fi
 
tmux attach -t $SESSIONNAME

I just then run /home/ryann/scripts/restoretmux.sh on the terminal and I get my Tmux session with 3 windows and 2 panes each.

How to Create and Delete System Templates in Processwire API

Listen to this Post. Powered by iSpeech.org

processwireAfter poring through Processwire’s awesome code for the past few hours, I’ve finally figured out how to create and delete system templates using Processwire’s API.

But, before I show you the code, a little background on why I needed one in the first place.

I’ve been creating this workflow module and wanted to create templates and fields that regular users won’t be able to use or delete. That’s the main reason. The second reason is simply because I thought it’d be cool to know how :D

Anyhow, here is the code for creating a system template:

/* We first make sure the template doesn't exist */
$temp = $this->templates->get($tname);
if(is_null($temp)){
   /* Every template needs a fieldgroup to add fields in */
   $fg = $this->fieldgroups->get($tname);
   if(!$fg){
      $fg = new Fieldgroup();
      $fg->name = $tname; //fieldgroup and template have the same name
      $fg->add($this->fields->get('title')); //required field
      $fg->save();
   }
 
   /* create our template */
   $temp = new Template();
   $temp->name = $tname;
   $temp->fieldgroup = $fg;
   $temp->noGlobal = 1;
   $temp->nameContentTab = 1;
   $temp->flags = $this->template->flags | Template::flagSystem;
 
   /* just something extra to let the user know what happened */
   if($temp->save()){
      $this->message('Created template: ' . $tname);
   } else {
      $this->error('Problem creating template: ' . $tname);
   }
}

And this is how you delete a system template:

$tname = 'mytemplate';
$temp = $this->templates->get($tname);
if(!is_null($temp)){
   //try to delete our custom template
   try{
      $fg = $temp->fieldgroup;
 
      $temp->flags = Template::flagSystemOverride;
      $temp->flags = 0;
      $temp->save();
 
      if($this->templates->delete($temp)){
         $this->message('Removed template: ' . $tname);
      } else {
         $this->message('Could not remove template: ' . $tname);
      }
 
      //TODO: check if other templates are using fieldgroup??
      $this->fieldgroups->delete($fg);
 
   } catch(Exception $e){
      //this can happen if *someone* uses our holder templates. not really sure
      $this->error('Fatal error while deleting template: ' . $tname);
   }
}

The core file I’ve looked at for creating the system template was wire/modules/Process/ProcessTemplate/ProcessTemplate.module within the executeSave() method.

For deleting, this was the forum thread that helped me: http://processwire.com/talk/topic/572-release-discussions/?p=4657

Sync (Push) from Local to Remote Database Using Capistrano

Listen to this Post. Powered by iSpeech.org

So, I could already deploy my site from local to remote using Capistrano. This was the easy part. Now, I needed to push my database from local to remote. Previously, what I did was to go to get a database dump of my local, go to remote database, drop/empty the tables in the target database and import the sql file I got from local. I was lazy, so I wanted something more… automatic :) At the same time, I also wanted to learn how to create custom capistrano tasks.

So, here’s my recipe:

45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
namespace :db do
   desc "Push db from local to remote"
   task :push, :roles => :web do
      random = rand( 10 ** 5 ).to_s.rjust( 5, '0' )
      filename = "pwcap-#{random}.sql"
      temp = "/tmp/#{filename}"
 
      puts 'db:push'
      puts stage
      l = wpdb[:local]
      r = wpdb[stage]
      puts "executing: mysqldump -u #{l[:user]} --result-file=#{temp} -h #{l[:host]} -p#{l[:password]} #{l[:name]}"
      system "mysqldump -u #{l[:user]} --result-file=#{temp} -h #{l[:host]} -p#{l[:password]} #{l[:name]}"
 
      #upload sql file to remote
      upload("#{temp}", "#{temp}", :via => :scp)
 
      remote_mysql = "mysql -u #{r[:user]} -p#{r[:password]} -h #{r[:host]} #{r[:name]}"
 
      ##
      # drop tables in remote database
      ##
 
      #get list of tables and prepare db command
      puts "DROPPING TABLES"
      tables = capture "#{remote_mysql} -e " + '"show tables;"'
      tables = tables.split(/$/).map{|t| t.strip}.reject{|t| t.empty?}
      tables.shift
      sql_drop = "DROP TABLE " + tables.map{|t| "#{t}"}.join(', ') + ';'
      puts sql_drop
      #run db command
      run remote_mysql + ' -e "' + sql_drop + '"'
 
      ##
      # Import db
      ##
      run "#{remote_mysql} < #{temp}"
 
      #cleanup
      run "rm #{temp}"
   end
end

I then run the command: cap STAGE_NAME db:push and capistrano does the rest.

This is assuming you have a multistage set-up i.e. dev, staging, production

and somewhere in your configuration, have the following:

28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#Database
#Set the values for host, user, pass and name for all stages
set :wpdb do
   {
      :local => {
         :host     => 'localhost',
         :user     => 'username',
         :password => 'password',
         :name     => 'databasename',
      },
      :dev => {
         :host     => 'localhost',
         :user     => 'username',
         :password => 'password',
         :name     => 'databasename',
      }
   }
end

How to Edit a Remote File over SSH Using Sublime Text and Rmate

Listen to this Post. Powered by iSpeech.org

I wanted to be able to edit a file in my computer but have it save on the remote server.

That’s when I found the rsub plugin for Sublime Text 2 and rmate.

What does Rmate do?

Rmate is a script that you install on the remote server – the server you want to edit files from. It was originally created for Textmate.

Basically, what it does is when you run this script on a file, it sort of *pushes* that file from the remote server down to your computer where your text editor – Sublime Text or Textmate – is waiting to *catch* it. Well, that’s the for dummies (like me) explanation. Technically, we use an SSH tunnel or something.

What does Rsub do?

Rsub is a plugin that you install on Sublime Text 2. This is the thing allows ST2 to *catch* the file *pushed* down from the server and edit the file.

Installation and Setup

  1. Install rsub plugin for ST2.
  2. SSH to your remote machine: ssh user@remote.com
  3. Download Rmate: curl https://raw.github.com/aurora/rmate/master/rmate > rmate
  4. Move Rmate to bin: sudo mv rmate /usr/local/bin so don’t need to specify the path to rmate script
  5. Make it executable: sudo chmod +x /usr/local/bin/rmate
  6. Done!

How to use

  1. Run Sublime Text 2 in your computer.
  2. SSH to remote: ssh -R 52698:localhost:52698 user@remote.com
  3. Rmate the file you want to edit locally: rmate file.php
  4. The file should open in ST2 in your computer.

Creating Symlink in KDE

Listen to this Post. Powered by iSpeech.org

I’m new to KDE – the desktop environment I went with when I installed Fedora 18. I’ve previously been using Ubuntu + Gnome + Nautilus (not the Unity version though, I think it sucks but that’s another story).

Anyway, one of the things I’m used to doing in Nautilus was creating symlinks using the mouse by right-clicking the file or folder that I wanted to create a symlink to, and in the context menu choose “Make Link” which is a great way of making symlinks without opening the command line.

Unfortunately, Dolphin – the default file manager Fedora 18 came with – didn’t have this in it’s context menu – or Service Menu. Anyway, it took me awhile to figure this out but it’s actually dumb easy.

Ctrl + Shift + drag

  1. Hold down Shift + Ctrl key. Don’t let go and go to #2.
  2. Left click + drag the file or folder that you want to create a symlink of.
  3. Drop. You should get a prompt to enter the file name for the symlink.
  4. Name your symlink and that’s it!

P.S. This works for

Editing Right-Click Action (Service Menu) in KDE

Listen to this Post. Powered by iSpeech.org

I just installed Fedora with KDE on my work station and wanted to edit the Service Menu – the menu you get when you right-click->Action.

I googled around and found this and this but both seemed to need to a bit more config editing than what I wanted to do. I wanted a simpler way of doing it.

Luckily, I found the KDE4 Service Menu Editor.

Just one snag though. I installed the Service Menu Editor on a fresh install of Fedora 18 by doing $ sudo ./setup.py install and I got the following error:

Install error

Basically, it says that I don’t have the required modules installed. So, if you get this, just type this out in your terminal (or konsole):

$ sudo yum install python-distutils-extra

Then install again: $ sudo ./setup.py install

How to Install Packages for End of Life Ubuntu Editions

Listen to this Post. Powered by iSpeech.org

I use Ubuntu 10.10. Have been for 4 years now. So, basically my installation has reached EOL (End of Life) and won’t receive any more updates/support as the longest supported editions (LTS editions) only span 4 years.

So, what happens when your edition reaches EOL?

First, you can no longer install new apps/packages using

apt-get install APPNAME

You also can’t update anything. This is because the repositories for the unsupported edition have been removed from the main servers.

The Good News

Repositories for unsupported editions aren’t removed off the face of the internet universe. They’re moved to http://old-releases.ubuntu.com/releases/.

There's hope for you yet

There’s hope for you yet

To use this new repository, we just need to change software sources in /etc/apt/sources.list. For Ubuntu 10.10, the file should look like this:

## EOL upgrade sources.list
# Required
deb http://old-releases.ubuntu.com/ubuntu/ maverick main restricted universe multiverse
deb http://old-releases.ubuntu.com/ubuntu/ maverick-updates main restricted universe multiverse
deb http://old-releases.ubuntu.com/ubuntu/ maverick-security main restricted universe multiverse

# Optional
#deb http://old-releases.ubuntu.com/ubuntu/ maverick-backports main restricted universe multiverse
#deb http://old-releases.ubuntu.com/ubuntu/ maverick-proposed main restricted universe multiverse

That’s it.

Resources

P.S.

Some of you might be asking why I haven’t bothered to upgrade my edition? At the time of this writing, latest version is at 12.10, codenamed Quantal Quetzal. So why not upgrade? Must be tons of new features. Plus it’s better security-wise.

The answer is simple really.

I have no time.

No time to troubleshoot why upgrade hung up. No time to change the default user interface from Unity back to Gnome. (Why would I change it you ask? Because I prefer it) No time to troubleshoot why my favorite app isn’t working after the upgrade. No time to…

I will keep using what I have until it stops working for me, or when a new app gets released that I really, really need but it only runs on the latest edition.

Git Tip: Delete a Remote Branch

Listen to this Post. Powered by iSpeech.org

There are a couple ways to delete a remote branch in Git and some ways will depend on the installed version:

git push origin --delete <branchName> [available in v1.7+]

which is just a wrapper to:

git push origin :branchName

Also, if you have version 1.7+ installed, you can also delete multiple remote branches with:

git push origin --delete branch1 branch2 branch3

Photo by lett -/\=

3 Services for Setting Up Cron Jobs

Listen to this Post. Powered by iSpeech.org

Photo by lett -/\=

Last year, I talked about how to set up Linux cron jobs in BlueHost to trigger WordPress’ pseudo-cron service. This is helpful when you want to automate certain tasks and execute scripts periodically – like sending reminders using my Email Reminder plugin for example.

Unfortunately, setting up cron jobs in your server requires a wee bit of technical know-how. Fortunately, there are services [some free] that can help you out.

Here are three of them.

WebCron.org

What I like about this service is that they offer an API for their customers to use. This allows developers to create applications on top of their service – like creating cron jobs within your WordPress dashboard for instance.

That said, their pricing is straight forward – pay as you go for as low as $ 0.00014 per launch [I am in no way affiliated with them].

 Visit the site

 GetCron.com

This service offers 3 yearly pricing tiers – Personal, Business and Enterprise – depending on the number of web cron jobs you want to run. They also offer a free 1 year account to use 1 web based cron job.

Key features include:

  • 5 minute script execution time-out
  • Timezone support for cron jobs – very helpful when you want your script to only execute at midnight Mountain Time but your server is located in Australia and the web cron service is in the Eastern seaboard.
  • No programming skills required
  • Very Easy and Intuitive – 3 Step Wizard to create even the most complicated time schedule for your web cron
  • Web Crons output tracking
  • Any script can be called – PHP, Ruby On Rails, JSP, ASP Classic, ASP.NET, Perl and others
  • Technical Support

View the site

SetCronJob.com

SetCronJob gives their members a set number of cron jobs that can be executed – called Points – per day. So, on the Free Account plan, you get 50 Points. This allows you to create two cron jobs that execute every hour [24 points x 2 jobs] or 50 cron jobs that execute once a day [1 point x 50 jobs].

Nuff said, view the site.

Creating Template Files With Python

Listen to this Post. Powered by iSpeech.org

The problem.

A few days ago, I was working on creating templates for a WordPress plugin. Basically, the templates allowed users of the plugin to easily add graphics to their blog posts and edit some parts of it via shortcode.

Now each template package essentially looked like this:

It had a couple of PHP files, a CSS file, the main button image and a couple of thumbnail images.

The task was pretty simple actually. Given the main button image, I was to create a small thumbnail image and a larger thumbnail image. I then needed to name the main button image into button.png. Then, I was to create a couple PHP files, data.php and template.php. Plus a stylesheet – style.css.

Each template package was to contain these same files with the same file names with the same code, save for a couple of ID numbers specific to each template.

Very easy.

I could just copy the files from the first template I created, modify the ID numbers in each file, then create thumbnail images out of the main image and name each correctly.

The problem was, there was 135 of them. And it looked like this:

I did the math and assuming I could create one template in 2 minutes, that was 135 x 2min = 270 minutes which was about 4.5 hours. Oh crap.

I needed a more intelligent way of creating the template packages (copy and paste is not intelligent). I needed to be able to generate the files with the correct code, resize the button image down to two thumbnail sizes, and rename this button image into button.png.

I knew PHP could probably do it but I wasn’t so good at mucking around with the file system.

And that’s when it hit me. Python. I’ve been meaning to learn Python for a long time now but had always put it off. And from what I’ve read from other users, Python was a very newbie-friendly language and very easy to pick up. So, what better time to learn the language than now? I could learn and solve a problem at the same time.

The solution

First thing I needed to do was to grab the file names of each button image. Googling around, I found this and this, from which I created the following:

1
2
3
4
5
6
7
import os;
 
image_dir = '/home/projects/design/pytest/edited';
new_dir = '/home/projects/design/pytest/new';
 
for file_name in os.listdir( image_dir ):
    print file_name;

Where file_name now contains the file name of the button image. Next, I needed to grab the template ID. Fortunately, the button images were named like so: original-1.png, original-2.png, original-3.png… where the numbers represented the template ID, so, RegEx to the the rescue:

1
2
3
4
5
6
7
8
9
10
11
12
import os;
import re;
 image_dir = '/home/projects/design/pytest/edited';
new_dir = '/home/projects/design/pytest/new'; 
for file_name in os.listdir( image_dir ):
    print file_name;
 
    match = re.search(r'[0-9]+', file_name);
    if( match ) :
        num = match.group();

Note: you need to import the regex module to use regular expressions.

Now that I have the file names and the IDs, I can now start creating the template directories. The template directories would be named like so: button1, button2, button3… and so on. So, I needed to know the absolute paths.

I also needed to create two thumbnail images based off the original image. Then, I also needed to copy the original image in to the template directory and rename it to button.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import os;
import re;
import shutil;
import Image;
 
image_dir = '/home/projects/design/pytest/edited';
new_dir = '/home/projects/design/pytest/new';
 
for file_name in os.listdir( image_dir ):
	#print file_name;
 
	match = re.search(r'[0-9]+', file_name);
	if( match ) :
		#grab the template ID
		num = match.group();
 
		#full path to original image
		original_image = os.path.abspath( os.path.join( image_dir, file_name ) );
 
		#full path to new template directory
		new_path = os.path.abspath( os.path.join( new_dir , 'button' + num ) );
 
		#full path of new button.png within the template directory
		new_image_path = os.path.abspath( os.path.join( new_path, 'button.png' ) );
 
		#full path of the thumbnail images
		new_image_thumb = os.path.abspath( os.path.join( new_path, 'thumbnail.png' ) );
		new_image_thumb_big = os.path.abspath( os.path.join( new_path, 'thumbnail-big.png' ) );
 
		#create the template directory if it is not created yet.
		if not os.path.isdir( new_path ):
			os.makedirs( new_path );
 
		#copy original image into the template directory with the file name button.png
		shutil.copy( original_image, new_image_path );
 
		#create the thumbnails
		size = 160, 100;
		thumb = Image.open(original_image);
		thumb.thumbnail(size, Image.ANTIALIAS );
		thumb.save(new_image_thumb,'PNG');
 
		size_big = 300,188;
		thumb_big = Image.open(original_image);
		thumb_big.thumbnail( size_big, Image.ANTIALIAS );
		thumb_big.save(new_image_thumb_big,'PNG');

I created the paths I needed. Then, created the template directory if it didn’t exist. I then copied the original image into the template directory with the new name button.png. After that, the two thumbnails were created using Python’s Image module.

Now, I just need to create the PHP and CSS files. Here we go..

49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
import os;
#CREATE THE FILES
 
#create data.php
data_content =  """<?php
return array(
'name' => 'Button %s',
'attributes' => array(
'width' => '300px',
'align' => 'center',
'url' => 'http://example.com/buy'
),
'content' => ''
);
""" %(num)
 
fo = open( os.path.abspath( os.path.join( new_path, 'data.php' ) ), 'w+' );
fo.write( data_content );
fo.close();
 
#create style.css
style_content = """.wpg-cart{ex}.alignleft{{ float: left; margin-right: 24px; }}
.wpg-cart{ex}.alignright{{ float: right; margin-left: 24px; }}
.wpg-cart{ex}.alignnone{{}}
.wpg-cart{ex}.aligncenter{{ clear: both; display: block; margin: 0 auto; }}
.wpg-cart{ex} img{{ background: none !important; border: none !important; padding: 0 !important; max-width: 100%; }}
""".format( ex=num )
 
fo = open( os.path.abspath( os.path.join( new_path, 'style.css' ) ), 'w+' );
fo.write( style_content );
fo.close();
 
#create template.php
template_content = """<?php
$atts = wpg_get_shortcode_atts();
$align = isset( $atts['align'] ) ? 'align'.$atts['align'] : 'alignnone';
$width = isset( $atts['width'] ) ? 'width: '.$atts['width'].';' : '';
?><div class="wpg-cart%s <?php echo $align; ?>" style="<?php echo $width; ?>"><a href="<?php echo $atts['url']; ?>"><img src="<?php echo wpg_get_template_url(); ?>/button.png" alt=""/></a></div>""" %(num)
 
fo = open( os.path.abspath( os.path.join( new_path, 'template.php' ) ), 'w+' );
fo.write( template_content );
fo.close();

Long story short, we created two PHP files, and one CSS file with the required code inside. The only difference within each was the template ID represented by the variable num.

When you run the script, the template directories with the files inside will be created for you. Like this:

No need to spend more than 4 hours copy pasting something over and over again.

Below is the full code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import os;
import os;
import re;
import shutil;
import Image;
 
image_dir = '/home/projects/design/pytest/edited';
new_dir = '/home/projects/design/pytest/new';
 
for file_name in os.listdir( image_dir ):
	#print file_name;
 
	match = re.search(r'[0-9]+', file_name);
	if( match ) :
		#grab the template ID
		num = match.group();
 
		#full path to original image
		original_image = os.path.abspath( os.path.join( image_dir, file_name ) );
 
		#full path to new template directory
		new_path = os.path.abspath( os.path.join( new_dir , 'button' + num ) );
 
		#full path of new button.png within the template directory
		new_image_path = os.path.abspath( os.path.join( new_path, 'button.png' ) );
 
		#full path of the thumbnail images
		new_image_thumb = os.path.abspath( os.path.join( new_path, 'thumbnail.png' ) );
		new_image_thumb_big = os.path.abspath( os.path.join( new_path, 'thumbnail-big.png' ) );
 
		#create the template directory if it is not created yet.
		if not os.path.isdir( new_path ):
			os.makedirs( new_path );
 
		#copy original image into the template directory with the file name button.png
		shutil.copy( original_image, new_image_path );
 
		#create the thumbnails
		size = 160, 100;
		thumb = Image.open(original_image);
		thumb.thumbnail(size, Image.ANTIALIAS );
		thumb.save(new_image_thumb,'PNG');
 
		size_big = 300,188;
		thumb_big = Image.open(original_image);
		thumb_big.thumbnail( size_big, Image.ANTIALIAS );
		thumb_big.save(new_image_thumb_big,'PNG');
 
		#CREATE THE FILES
 
		#create data.php
		data_content =  """&lt;?php
		return array(
		'name' =&gt; 'Button %s',
		'attributes' =&gt; array(
		'width' =&gt; '300px',
		'align' =&gt; 'center',
		'url' =&gt; 'http://example.com/buy'
		),
		'content' =&gt; ''
		);
		""" %(num)
 
		fo = open( os.path.abspath( os.path.join( new_path, 'data.php' ) ), 'w+' );
		fo.write( data_content );
		fo.close();
 
		#create style.css
		style_content = """.wpg-cart{ex}.alignleft{{ float: left; margin-right: 24px; }}
		.wpg-cart{ex}.alignright{{ float: right; margin-left: 24px; }}
		.wpg-cart{ex}.alignnone{{}}
		.wpg-cart{ex}.aligncenter{{ clear: both; display: block; margin: 0 auto; }}
		.wpg-cart{ex} img{{ background: none !important; border: none !important; padding: 0 !important; max-width: 100%; }}
		""".format( ex=num )
 
		fo = open( os.path.abspath( os.path.join( new_path, 'style.css' ) ), 'w+' );
		fo.write( style_content );
		fo.close();
 
		#create template.php
		template_content = """&lt;?php
		$atts = wpg_get_shortcode_atts();
		$align = isset( $atts['align'] ) ? 'align'.$atts['align'] : 'alignnone';
		$width = isset( $atts['width'] ) ? 'width: '.$atts['width'].';' : '';
		?&gt;&lt;div class="wpg-cart%s &lt;?php echo $align; ?&gt;" style="&lt;?php echo $width; ?&gt;"&gt;&lt;a href="&lt;?php echo $atts['url']; ?&gt;"&gt;&lt;img src="&lt;?php echo wpg_get_template_url(); ?&gt;/button.png" alt=""/&gt;&lt;/a&gt;&lt;/div&gt;""" %(num)
 
		fo = open( os.path.abspath( os.path.join( new_path, 'template.php' ) ), 'w+' );
		fo.write( template_content );
		fo.close();

On Linux, open a terminal into the directory where the python script is at and run the script using the command:

python python_script.py

Assuming the file name of your script is python_script.py

And one last thing, this is actually my first Python script. I’ve never coded Python before, so I hope this article is a testament to how easy it is to learn this language.