Perl on the command line (part 1)

[ Perl tips index ]
[ Subscribe to Perl tips ]

Occasionally we find a task that only ever needs to be done once. Perhaps we need to change a file so that all strings A002 become B005, or we want to find out how many times a particular IP address accesses the web-server today. In these cases, rather than use a throw-away script, we may be able to write our script directly onto the command line.

Keep in mind as you do this though, that sometimes throw-away scripts turn into programs that become essential to the business. If you think you're ever likely to run this same program again, or if it is non-trivial, write it into a program, comment it, use strict and warnings, as well as the appropriate modules and keep it. You'll be glad you did.

Using the execute switch (-e) to convert from epoch-time

Let's say that you've got a timestamp in seconds from the epoch; the number of seconds since midnight, 1st January, 1970 GMT. This time format is used by a number of applications, and has the advantage of being an absolute measurement of time that is independent of timezone or daylight savings. It's also completely useless to most humans. By default, the squid proxy server records times in seconds from the epoch.

We can use Perl to convert epoch-time to local time very easily, and we can do so on the command-line using Perl's execute switch, -e:

        perl -e 'print scalar(localtime(1150946643)).qq{\n}';

Under Perl 5.10, we can use the capital -E switch to execute code, but turning on all the new 5.10 features first:

        perl -E 'say scalar localtime(1150946643)'

The qq{\n} represents a newline character, which you may more commonly see written as "\n". We use scalar to force localtime into a scalar context. Without this, Perl would instead return us a long list consisting of the year, month, time, hour, minute, second and so forth. Not exactly what we're after.

When writing a script on the command line, it's always recommended that you use q{} for single quotes, and qq{} for double quotes. This avoids any unwanted interaction with the shell, and can also make your code visually easier to read.

To perform multiple operations, just use semi-colons between your statements, in the same way that you do in a program:

        perl -e 'foreach(<*.txt>) { s/.txt$//; rename(qq{$_.txt},qq{$_-2006.txt}) }'

This moves all files with a .txt extension to instead end with -2006.txt.

Note

When using the -e and -E switches, you need to be very careful of interactions with the shell. Most Unix shells pass single-quoted strings to the application without alteration. DOS and Windows shells, on the other hand, use double quotes for this purpose:

        # Unix, single-quotes   
        perl -e'print scalar(localtime(1150946643)).qq{\n};'
        # Windows, double-quotes
        perl -e"print scalar(localtime(1150946643)).qq{\n};"

In these notes we'll be using single-quotes when working on the command-line. If you're working on a Windows system, then you'll need to change these to double-quotes before trying any examples.

Script-less programming

You may have a snippet of Perl that you wish to execute, perhaps from an e-mail or web page, but which you don't want to save as a permanent program. In that case you can invoke Perl and give it a script on STDIN:

        % perl
        foreach(<*.txt>) {
                s/.txt$//;
                rename("$_.txt","$_-2006.txt");
        }

This will tell you of syntax errors immediately, but script execution will not start until you send Perl an end-of-file character, or more commonly known as EOF. On Unix systems this is done by hitting CTRL-D at the start of a line, and under Windows is done by hitting CTRL-Z at the start of a line.

If your program accepts input from STDIN, you will need to provide its input after you've sent the EOF character and then send EOF again. In this case, you're almost certainly better off writing your code into a file.

Printing switch (-p)

Using -p tells Perl to act as a stream editor. It will read input from STDIN, or from files mentioned on the command line, and place each line of input into $_. The body of your program is then executed, and the contents of $_ are printed. It's most commonly used with Perl's substitution operator s///, which is covered in the regular expressions chapters of this course.

The following command line snippet can be used to correct a common spelling mistake in one of our documents:

        perl -pe 's/freind/friend/g' essay.txt > spellchecked-essay.txt

It's the same as writing:

        while(<>) {
                s/freind/friend/g;
                print;
        }

As a more advanced example, the following snippet can be used to convert seconds from the epoch time-stamps into human readable dates for squid logfiles:

        perl -pe's/^([\d.]+)/localtime($1)/e' access.log

It works by finding a number at the start of each line (the timestamp), and replacing it with the result of calling localtime on that timestamp.

Non-printing switch (-n)

        perl -ne 'print if /perltraining\.com\.au/'

Using -n makes Perl act almost the same as -p. However, the print line is excluded. This allows us to write code like the above which only prints when we want it to. It is equivalent to:

        while(<>) {
                print if /perltraining\.com\.au/;
        }

Module switch (-M)

Perl has a great number of useful modules, and we may wish to use these on command-line programs. We can load them quickly and easily using the -M switch. The following example prints what Perl can find in our environment using Data::Dumper:

        perl -MData::Dumper -e 'print Dumper(\%ENV);'

Multiple modules can be used by including multiple -M flags.

If you need to provide options to the module, you can do so as follows:

        perl -MFatal=open,close -e 'open(my $file, q{> /tmp/foo}); 
        print {$file} qq{12345\n};'

The above program will die with an error if the open fails, even though we are not explicitly catching this error. This is because of our use of the Fatal module. It is equivalent to:

        use Fatal qw(open close);
        open(my $file, q{> /tmp/foo});
        print {$file} qq{12345\n};

Further information

For more information on these switches read perldoc perlrun. Further switches will be covered in a later tip.

[ Perl tips index ]
[ Subscribe to Perl tips ]


This Perl tip and associated text is copyright Perl Training Australia. You may freely distribute this text so long as it is distributed in full with this Copyright noticed attached.

If you have any questions please don't hesitate to contact us:

Email: contact@perltraining.com.au
Phone: 03 9354 6001 (Australia)
International: +61 3 9354 6001

Valid XHTML 1.0 Valid CSS