Perl: A script that contains valid Perl and Python code

Perl has a cool runtime option named -x that causes Perl to scan a file for the first shebang line with "perl" in it, and start executing there. This allows you to embed Perl in other files, like text files, or email files.

This got me thinking about embedding a working Perl script in another file. Python allows you to have large multi-line comment blocks using triple quotes """ blocks around your text. Using these comment blocks I was able to embed Perl code inside of a Python script. Effectively you can have a single file that is executable by Perl (with -x) and Python. I wrote up a quick proof-of-concept dual language script.

python dual-perl-python.py
perl -x dual-perl-python.py

Gives varying output:

Hello world from Python v3.8.7
Hello world from Perl v5.30.3
Leave A Reply

Perl: Simple file cache

I need a simple disk based object cache and Cache::File was overkill. I wrote my own dependency free (only core modules) version:

cache($key);                     # Get
cache($key, $val);               # Set expires is 1 hour (default)
cache($key, $val, time() + 900); # Set expires in 15 minutes
cache($key, undef)               # Delete

I purposely wrote it small so it can be copy/pasted in to other scripts simply. I wrote a more robust implementation with some basic tests as well. When an entry is fetched that is expired it will be removed from disk. Abandoned cache entries will persist on disk until cache_clean() is called.

sub cache {
    use JSON::PP; use Tie::File; use File::Path; use Digest::SHA qw(sha256_hex);

    my ($key, $val, $expire, $ret, @data) = @_;

    my $hash = sha256_hex($key || "");
    my $dir  = "/dev/shm/perl-cache/" . substr($hash, 0, 3);
    my $file = "$dir/$hash.json";
    mkpath($dir);

    tie @data, 'Tie::File', $file or die("Unable to write $file"); # to r/w file

    if (@_ > 1) { # Set
        $data[0] = encode_json({ expires => int($expire || 3600), data => $val, key => $key });
    } elsif ($key && -r $file) { # Get
        eval { $ret = decode_json($data[0]); };
        if ($ret->{expires} && $ret->{expires} > time()) {
            $ret = $ret->{data};
        } else {
            unlink($file);
            $ret = undef;
        }
    }

    return $ret;
}
Leave A Reply

Perl: Create a variable pointer to a built-in filehandle

I have a function that takes a filehandle for an argument. This is easy for filehandles that you create with open() but gets more complex if you try to use one of the automatic filehandles. Using the * syntax you can create a pointer to the symbol table for that entry.

$fh = \*STDIN;
$fh = \*STDOUT;
$fh = \*DATA;

Once it's a standard scalar variable it can easily be passed to a function.

Leave A Reply

Perl: Run a shell command and capture STDOUT and STDERR separately

Often I'll want to run a shell command and capture STDOUT and STDERR separately. I wrote a function to simplify this process:

my $x    = shell_cmd($cmd);
my $exit = $x->{exit};
my $err  = $x->{stderr};
my $out  = $x->{stdout};
# Run a command and return STDOUT/STDERR/Exit
sub shell_cmd {
    use IPC::Open3;
    my ($cmd) = @_;
    my ($STDIN, $STDOUT, $STDERR, $pid, $ret) = (1,2,3,undef,{});

    # If it's an arrayref run it directly (no shell)
    if (ref($cmd) eq 'ARRAY') {
        $pid = IPC::Open3::open3($STDIN, $STDOUT, $STDERR, @$cmd);
    } else {
        $pid = IPC::Open3::open3($STDIN, $STDOUT, $STDERR, $cmd);
    }
    waitpid($pid, 0);

    # Set FH slurp mode
    local $/ = undef;

    $ret->{exit}   = int($? >> 8);
    $ret->{stderr} = readline($STDERR);
    $ret->{stdout} = readline($STDOUT);
    $ret->{cmd}    = $cmd;

    return $ret;
}
Leave A Reply

HTML5: Text to speech

HTML5 includes some text-to-speech processing that can be invoked via JavaScript. I wrote a quicky script to allow you to paste text and have it read for you. It's great to proofread emails before you send them.

Leave A Reply

Web based bandwidth converting tool

I was ripping DVDs and needed to calculate the final output size given a specific bitrate. I got tired of doing the math over and over so I wrote a tool to do it for me.

Bandwidth converter

Leave A Reply

Linux: Find command with "or"

Linux has a very powerful find command, but it can be daunting to get all the options right. Recently I needed to find all my new .txt and .pl files. To do this you need to be able to say "find all the files that are text OR perl". In Linux find that looks like:

find /dir/path/ -type f \( -name '*.txt' -or -name '*.pl' \) -ctime -7

The spaces after and before the surrounding parenthesis are required or you will get weird error messages. Lots of research and examples borrowed from geeksforgeeks.org.

Leave A Reply

NPR has a great audio quality comparison test

NPR has an amazing quiz for various bitrates of compressed audio. It will test to see if you can hear the quality difference three different bitrates: 128Kb/s, 320Kb/s, and uncompressed. I've taken the test several times and I'm unable to hear the difference for anything above 128Kb/s. I even used headphones to get the best experience and it didn't help.

Leave A Reply

Perl: Nested subroutines

Perl doesn't support nested sub-routines natively, but you can fake them by using functions defined at runtime.

sub a {
    local *b = sub {
        return 123;
    };

    return b();  # Works as expected
}

b();  # Error: "Undefined subroutine &main::b called at ..."

Some times nested functions can be useful for simplifying readability of code while also allowing simple copy/paste for code re-use.

Leave A Reply

Books of 2021

List of books I read in 2021. Also see the list of 2020. The date indicated denotes the date I started reading the book.

2021-01-01 - Ready Player Two - 366 pages
2021-01-06 - The Institute - 561 pages
2021-01-14 - Turtles All the Way Down - 286 pages
2021-01-19 - Mindfulness In Plain English - 196 pages
2021-01-22 - Catcher In the Rye - 214 pages
2021-01-26 - The Odyssey - 303 pages
2021-02-01 - Ringworld - 342 pages
2021-02-07 - The Ringworld Engineers - 354 pages
2021-02-16 - The Ringworld Throne - 352 pages
2021-02-21 - Ringworld's Children - 284 pages
2021-02-26 - Protector - 218 pages
2021-03-01 - Arguing with Zombies - 414 Pages
2021-03-08 - Desperation - 690 Pages
2021-03-18 - The Sword in the Stone - 256 Pages
2021-03-22 - Action Park - 337 Pages
2021-03-27 - The Iron Giant - 93 Pages
2021-03-28 - Middle Game - 528 Pages
2021-04-06 - Regulators - 475 Pag

2021-xx-xx - Looking for Alaska - 224 Pages

2021-xx-xx - Hitchhiker's Guide to the Galaxy - 209 pages
2021-xx-xx - The Restaurant at the End of the Universe - 217 pages
2021-xx-xx - Life, the Universe, and Everything - 182 pages
2021-xx-xx - So Long, and Thanks For All the Fish - 204 pages

Leave A Reply - 1 Reply

Proxmox: Disable registration popup for 6.3

To disable the registration popup on Proxmox 6.3 run the following command:

perl -0777 -pi -E 's/if \(res === null \|.*?\) \{/if (false) {/s' /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js
Leave A Reply - 1 Reply

Perl: Slurp entire file in a one liner

I need to change some text in a file that's spread across multiple lines. This means perl -pE won't work because it treats each line as a separate regexp. Reading the file in to one big string and then running a multiline regexp is the best solution.

Using -0777 tells Perl to read the entire file in to one string and allows multi-line regexps to work as intended.

If you have an input file with the content like:

if (foo
    && bar && !true) {
    # Do stuff
}

You can change the if statement with a one-liner like this:

perl -0777 -pE 's/\(foo.*?\)/(test)/s' /tmp/input.txt
Leave A Reply

Eagleson's law

“Any code of your own that you haven't looked at for six or more months might as well have been written by someone else.” - Eagleson's Law

Seems about right.

Leave A Reply

Bash: Using previous command's parameters

Bash allows you to save some typing by referencing the previous command's parameters via a variable. If you want to reference the first parameter from the previous command you would use !^ and if you want the last parameter you would use !$. A real world example would be something like this:

mkdir /long/dir/structure/new_dir
cd !$

This would make a new directory and then change to that directory. Alternately you can reference numbered parameters using !:2 to reference the 2nd parameter.

Leave A Reply

Apache: Blocking access to certain file types with .htaccess

My templating system uses .stpl files for it's definitions. I do not want to serve these files directly to my users so I used an .htaccess file to block them.

<Files ~ "\.stpl$">
    Order allow,deny
    Deny from all
</Files>
Leave A Reply