Log results of perl scripts

While you are debugging perl scripts, the default for print statements is to display on the console. Often you want to have more info than fits nicely on the console or you want to be able to search through the results. In that case you can redirect the print commands with a simple redirect. e.g.


./perl_test.pl > test_results.txt

Once the script is debugged and running as a cron job, you might still want to see that it has successfully completed or has generated errors. In that case, redirecting the STDOUT and STDERR to log files is what you want to do.

I created a directory /var/log/My_logs and chmodded it to 755 and chowned it to admin. Then I added two lines at the beginning of the file.


#! /usr/bin/perl

use strict;
use warnings;

open(STDOUT, '>>',  $0 . ".log") or die "Can't open log";
open(STDERR, '>>',  $0 . ".error.log") or die "Can't open error log";

A couple of notes. the >> appends the results to the current file. $0 is the name of the perl script that is running. So if I run perl_test.pl, the log file is perl_test.l.log. Also note that that is the complete file path and file name. If you are running the script manually, you might want to create log files in the same directory as the script. But if the script is part of a cron job, you might be better off writing the log files to /var/log/. And you probably don’t want the entire script do die if the log file can’t be opened.

An alternative way to do the same thing is to split the file name into parts with the fileparse function in the File::Basename module.


#! /usr/bin/perl

use strict;
use warnings;

 my($filename, $directories, $suffix) = fileparse($path);

open(STDOUT, '>>', "/var/log/My_Project_logs/" . $filename. ".log");
open(STDERR, '>>', "/var/log/My_Project_logs/" . $filename. ".error.log");

If you run the script as you, but later want it to be run as a cron job, make sure you change the permissions of the log files so that they match the permissions of the owner of the script.

If you write out a bunch of stuff, make sure you clean out the log files from time to time. Otherwise, set up a log rotation in /etc/logrotate.d/.

Fix hyphenation in WordPress themes

A new blog that I installed using the TwentyFifteen theme has annoying hyphenation on the posts. I found an easy fix online. Open the style.css file and insert this at the end.


.entry-content,
.entry-summary,
.page-content,
.nav-links,
.comment-content,
.widget
 {
   -webkit-hyphens: none;
   -moz-hyphens:    none;
   -ms-hyphens:     none;
   hyphens:         none;
}

Perl gotcha’s–equality

If you try to compare strings using ==, and you have included the use warnings pragma, you will get a warning, as in the example below. However, Perl will still attempt to convert the string into a number. If the string starts with numbers, Perl will use these, otherwise the string equates to 0.

So my conditional,


if ($device_id == '5G0E3663') { ... }

compares two zeros and always returns true. Which in my case made bad things happen.
The correct way to compare strings is:


if ($device_id eq '5G0E3663') { ... }

h/t perlmeme.

for loops in bash

I don’t do much shell scripting, but every once in a while I use it to automate things. I was playing around with bash today and thought this might interest others.

Define an array variable
$ servers=(server purple yellow dan);
$ echo $servers
server

Redefine it.
$ servers=(firstserver server purple yellow dan);
$ echo $servers
firstserver

That’s not what I want. So how do we access the values? Let’s try a for loop.
$ for name in $servers; do echo $name; done;
$ echo $servers
firstserver

Well that didn’t do it. Let’s try to access the second value with array notation.
$ for name in $servers; do echo $servers[1]; done;
firstserver[1]

If you look carefully at this you’ll notice that what is happening is that you are concatenating the return value from $server with [1]. Try it again with this line.

$ for name in $servers; do echo $servers[a]; done;
firstserver[a]

And again.
$ for name in $servers; do echo $servers.a; done;
firstserver.a

As long as you use a character that is not a valid part of a variable name, you get concatenation.
e.g. don’t use an alphanumeric.
$ for name in $servers; do echo $serversabc; done;

There is no variable called serverabc, so you get a blank line.

It turns out that bash has weird syntax for working with variables.
$ echo ${servers[2]}
purple

Add another value.
$ servers[5]=finalvalue
$ echo ${servers[5]}
finalvalue

So how about we separate out the loop variable like this?
$ for name in $servers; do echo $servers${name}; done;
firstserverfirstserver

Well, we’re getting warmer.
$ for name in $servers; do echo $name; done;
firstserver

This is getting frustrating. Let’s back up and try just listing a bunch of stuff in a list.
$ for name in firstserver server purple yellow dan finalvalue; do echo $name; done;
firstserver
server
purple
yellow
dan
finalvalue

So we can make a for loop iterate through items, but the normal way of accessing elements of an array doesn’t work in bash. It turns out that you need special syntax.

$ echo ${servers[@]}
firstserver server purple yellow finalvalue finalvalue

And to loop through everything like we wanted to do at the start.
$ for name in ${servers[@]}; do echo $name; done;
firstserver
server
purple
yellow
dan
final value

That wasn’t so hard was it?

Put footer at the bottom of the page

This only works if the page content is not bigger than the window.
Try it yourself or check it out at FixedFooter.


<!DOCTYPE html>
<html lang="en">

<head>
  <title>Fixed Footer Example</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

  <style type="text/css">
  html, body, #container {
      height: 100%;
      margin: auto;
      text-align: center;
  }

  #footer {
        position:absolute;
        bottom:0;
        width:100%;
        margin: auto;
        height:60px;
        text-align: center;
    }

  </style>
</head>
<body>

<div id="container">
    <h1>This is the main content</h1>
    <p>If it is bigger than the window, then the footer will play over it.</p>
    <p>The footer can be inside or outside of the container.</p>
</div>

<div id="footer">
    <p>This is the footer content.</p>
</div>

</body>
</html>