Learn Perl with this temperature-conversion script

467 readers like this.
code.org keynote address

Opensource.com

Over the years I've learned a number of programming languages on my own, including Perl. One learning tool I figured out is to use some sort of language reference to avoid the frustration of working through several chapters in a manual just to figure out a starting point.

Another good learning trick is to find a Perl program that does something similar to what you want to do, then play with it to gradually modify its behavior, using your reference when you get stuck. Eventually you become able to start from scratch after you've formulated some idea of what you want to do, and then translate that into a set of programming instructions.

A few years ago, while in the process of a collaboration for writing a manual for Scribus, I was spending quite a bit of time on freenode.net on the Scribus channel and talking to my German collaborator and others who mostly lived somewhere in Europe. You end up having a lot of conversations about all sorts of topics, and anywhere in the world you talk about the weather, but of course they're talking Celsius temperatures while I'm experiencing Fahrenheit. So I made a little utility in Perl to see what 14 °C is, or maybe instead of telling them my weather in °F, I'd be able to give them a number in °C.

Let's use this to talk a bit about Perl.

#!/usr/bin/perl -w
print "\nThis is the program for Fahrenheit to Celsius\n 
and Celsius to Fahrenheit temperature conversion\n\n";
$temp = $ARGV[0];
$f1temp = $temp . "°F";
$ctemp = ($temp - 32)* 5.0/9.0;
$rtemp = sprintf("%.1f", $ctemp);
$c1temp = $rtemp . "°C";
print "$f1temp is $c1temp\n\n";

$ftemp = $temp* 9.0/5.0 + 32;
$rtemp = sprintf("%.1f", $ftemp);
$c2temp = $temp . "°C";
$f2temp = $rtemp . "°F";
print "$c2temp is $f2temp\n\n";

I named this tempconv.pl, so the first thing to point out is that you name a file with a .pl extension to indicate that this is a Perl script. Next, look at the first line. It begins with these characters: #! This has a name, shebang, after which it's telling your computer where to find the interpreter, and the -w is asking for warnings about mistakes I may have made while writing this script. This line has to be the first line of the script.

The second line is just a little message to myself to confirm what this is doing, and of course not only is this part of the output, but I can read this when I look at the file, so in this case it is the full extent of the documentation for this script. This \n you see repeatedly is to have the printout (onscreen in this case) add a newline, or carriage return. It's easier to read if you break the output up a bit. I used double quotes, which behave differently from single quotes. For example the \n inside single quotes is printed literally; it is not interpreted and does not create a new line.

The third line finally gets to the meat of what we want to run this for. Notice all these words or word fragments beginning with $. All variable names must begin with a special character. The $ indicates a scalar variable, or in other words, a variable with a single value. ARGV is a special variable name used by Perl to refer to any input sent to the script when the program is run.

I could in fact have entered several numbers, tempconv.pl 45 23 38, in which case these three values create an array, @ARGV, from which we might specify $ARGV[0], which would be 45, or $ARGV[1] for 23, and so on. As this script is written it won't matter how many values you include, since it's only going to use the first value. (We'll get back to this later.)

To convert a temperature, type tempconv.pl 45 to convert the value 45. ARGV refers to that input, 45.

Next, some interesting things happen. Notice how I assign a string value of 45 °F to the variable $f1temp (the period is a concantenation operator to glue these two together). In the next line, I take the same input and perform mathematical operations with it. So was 45 a string or a number? Both, obviously. You should be able to recognize the formula for conversion of a Fahrenheit temperature to Celsius in ($temp - 32)*9.0/5.0.

All that's left is to print the result, but I want to make sure this comes out as a floating point number with one decimal place, that's what the sprintf command is doing.

The remainder of this script simply assumes that the 45 was in Celsius and converts to Fahrenheit, so in total the output of this script is:

This is the program for Fahrenheit to Celsius
 and Celsius to Fahrenheit temperature conversion

45°F is 7.2°C

45°C is 113.0°F

It may seem odd I would do this, but what happened was that originally I made two scripts, one named celsius.pl and the other fahren.pl, and each only did one calculation. The problem was that after some time went by, I forgot whether celsius.pl wanted a Celsius value or it was making one. It seemed to me the simplest thing was to just combine the operations, give both answers and keep usage simple. To further the simplicity, I also created an alias to run in Bash, called temp, which saves typing not only the entire filename, but also the path to it.

A not so difficult addition would be to create a loop, so that more than one value might be entered, and serial calculations take place. The main consideration is to detect how many values have been entered to avoid generating errors. More importantly, I haven't seen the need for this. But let's mention at this point a feature of Perl you may have noticed, which is that each line ends in a semicolon except for the first one. I should qualify that by saying that each executable statement ends with a semicolon. For example, let's say we wanted to add an optional message at the end based on a conditional:


if ($rtemp > 99) {
	print "Wow! That's hot!\n\n";
}

The executable part still ends with a semicolon, but the if conditional has its own structure, using curly brackets to corral all the lines that will be executed if the condition is met. Typically these are indented so they stand out more easily when you read the script.

It's easy enough to imagine taking what you see here and making various other little utilities to convert weights, distances, typographic measurements, and so on, and in fact I've done a number of these.

Tags
Greg Pittman
Greg is a retired neurologist in Louisville, Kentucky, with a long-standing interest in computers and programming, beginning with Fortran IV in the 1960s. When Linux and open source software came along, it kindled a commitment to learning more, and eventually contributing. He is a member of the Scribus Team.

9 Comments

You might check how up to date your Perl is before publishing an article like this. Using '-w' on the shebang line like that when Perl 5.6 was released in 2000. These days, we put "use warnings" in our programs instead. We also like to encourage people to include "use strict" as (amongst other things) it forces you to declare your variables.

One of the things I've always liked about Larry Wall is his self-professed laziness, as well as his humor. In a geeky sort of way, Learning Perl is a very funny book to read.
I tend to be of the "if it ain't broke, don't fix it" school, and this script continues to work for me with the Perl that comes with Fedora 24.

I agree. And here is an extra I did with an alias

$ vi .bashrc
alias jdegrees='perl /path/2/tempconv.pl $1'
$ . .bashrc
$ jdegrees 32

Now from anywhere and any place on the command line - I can run your program. Added an alias to .bashrc, refreshed .bashrc and they learned how to be even lazier ;-)

In reply to by Greg P

One of the nice things about Perl is that There Is More Than One Way to Do It (TIMTOWDI). Here is your script with the minimal changes required to be translated to Perl 6:

print "\nThis is the program for Fahrenheit to Celsius\n
and Celsius to Fahrenheit temperature conversion\n\n";
my $temp = @*ARGS[0];
my $f1temp = $temp ~ "°F";
my $ctemp = ($temp - 32) * 5/9;
my $rtemp = sprintf("%.1f", $ctemp);
my $c1temp = $rtemp ~ "°C";
print "$f1temp is $c1temp\n\n";

my $ftemp = $temp* 9/5 + 32;
$rtemp = sprintf("%.1f", $ftemp);
my $c2temp = $temp ~ "°C";
my $f2temp = $rtemp ~ "°F";
print "$c2temp is $f2temp\n\n";

Before I scrutinize, it's always nice to see more people use Perl, so I hope to see more like this, and don't take my comments too hard, I'm just trying to help hopefully without being too negative. That being said...

you can use a recent Perl version, like "use v5.18.0;" and replace your "print" statements with "say" statements, which automatically add a line break after your string or object.

It's also recommended to not use system Perl, and instead to "#!/usr/bin/env perl" instead.

Also consider your use case, what if someone tries to run the script without any arguments? For reference, you can check James Clark's blog (at http://blog.lazycat.com.au/), where he's posted some of his Perl 6 and Perl 5 scripts, which show a number of best practices.

Of course, you get errors. I generally don't mind errors if they're easy to understand, and "use of uninitialized value..." is pretty easy.

In reply to by Tim Van den La… (not verified)

Oh, I wasn't trying to suggest for a second that your code wouldn't work. It does, of course. It's just that when I'm writing for public consumption, I like to ensure I'm using current best practices.

Here's how I'd write your program:

#!/usr/bin/perl

use strict;
use warnings;

print "\nThis is the program for Fahrenheit to Celsius\n" .
"and Celsius to Fahrenheit temperature conversion\n\n";

my $temp = shift;

printf "%s°F is %.1f°C\n\n", $temp, ($temp - 32) * 5 / 9;
printf "%s°C is %.1f°F\n\n", $temp, ($temp * 9 / 5) + 32;

I like the simplicity of what you wrote. I'm certainly not trying to present myself as a Perl expert, more like someone who has learned some things on his own, and I know it shows.
Having looked up various references on the web, it seems like many of them would frighten people away. I was hoping here to try to do a thorough dissection of a small program in an unscary way.

In reply to by Dave Cross (not verified)

Was looking at this as well, and came up with a very similar answer to you there Dave!

Taking your answer one step further (or atleast, my version of it), you can loop over it very easily with the following method:

#! /usr/bin/env perl

use strict;
use warnings;

print "\nThis is the program for Fahrenheit to Celsius\n"
. "and Celsius to Fahrenheit temperature conversion\n\n";

while ( my $temp = shift ) {
my $ctemp = ($temp - 32) * 5.0/9.0;
my $ftemp = ($temp * 9.0/5.0) + 32;

printf "%.1f°F is %.1f°C\n\n", $temp, $ctemp;
printf "%.1f°C is %.1f°F\n\n", $temp, $ftemp;
}

This version allows you to pass multiple numbers, and it will convert all of them!

In reply to by Dave Cross (not verified)

Creative Commons LicenseThis work is licensed under a Creative Commons Attribution-Share Alike 4.0 International License.