echo5 has asked for the wisdom of the Perl Monks concerning the following question:

Greetings Monks, long time listener.....first time caller

I am attempting to accomplish something that I'm sure is probably dumb but I'm a hack (I admit it freely) and trying to deal with some ingested binary data in a way that makes sense in my brain (likely root of problem). I am ingesting binary output to stdout from a command run previous to the below code. Everything works as expected in the below code EXCEPT when I need to compare the value of previously defined variable (eg: $blu) by calling it in a foreach later where the string "blu" is an element and I try to call $blu by calling its element value in the foreach loop ${"index"} when $index equals blu, red, etc.

No matter what I try...${index}, ${'index'}, ${"index"} I can never draw in the value of $blu, $red, $grn or $ylw to evaluate whether or not it equals the value 01.

Thanks to all who take a moment to consider my quandary. Like I said I'm a hack and I'm beating my head against the desk.

{ chomp; my $dataout = $_; my @bytes = unpack( 'x252' . 'H2' x200, $dataout); my ($blu, $red, $grn, $ylw) = (@bytes[0], @bytes[12], @by +tes[56], @bytes[120]); my %humanize = ( 'blu' => 'Blue', 'red' => 'Red', 'grn' => 'Green', 'ylw' => 'Yellow' ); foreach my $index (blu, red, grn, ylw) { if (${"index"} != 01) { syslog('warning', "Color val +ue bad $humanize{$index}"); $status_code = 1; } } }

Replies are listed 'Best First'.
Re: Calling a variable value as a variable
by jwkrahn (Abbot) on Dec 12, 2018 at 04:46 UTC
    my ($blu, $red, $grn, $ylw) = (@bytes[0], @bytes[12], @by +tes[56], @bytes[120]);

    If you had warnings enabled you would have received these messages:

    Scalar value @bytes[0] better written as $bytes[0] at -e line n. Scalar value @bytes[12] better written as $bytes[12] at -e line n. Scalar value @bytes[56] better written as $bytes[56] at -e line n. Scalar value @bytes[120] better written as $bytes[120] at -e line n.

    As to your problem, use a hash:

    { chomp; my $dataout = $_; my %humanize; @humanize{ qw/ Blue Red Green Yellow / } = ( unpack 'x252 +' . 'H2' x 200, $dataout )[ 0, 12, 56, 120 ]; foreach my $index ( qw/ Blue Red Green Yellow / ) { if ( $humanize{ $index } eq '01' ) { syslog( 'warnin +g', "Color value bad $humanize{$index}"); $status_code = 1; } } }
Re: Calling a variable value as a variable
by eyepopslikeamosquito (Archbishop) on Dec 12, 2018 at 08:00 UTC

    To avoid pulling out large chunks of hair and depositing them by the keyboard in future, always start your scripts with:

    use strict; use warnings;

    As for why symbolic references should be avoided, see the classic three part series by MJD: part 1 and part 2 and part 3.

Re: Calling a variable value as a variable
by Marshall (Canon) on Dec 12, 2018 at 07:56 UTC
    I haven't looked closely at your unpack().

    This:

    my ($blu, $red, $grn, $ylw) = (@bytes[0], @bytes[12], @bytes[56], @byt +es[120]);
    may not be what you want.
    my ($blu, $red, $grn, $ylw) = ($bytes[0], $bytes[12], $bytes[56], $byt +es[120]);
    is the same. I'm not sure that is what you want either!
    You are getting scalar values at particular byte offsets into the @byte array.
Re: Calling a variable value as a variable
by davido (Cardinal) on Dec 13, 2018 at 00:13 UTC

    Symbolic references are absolutely the wrong way to go about the problem you are trying to solve, as are global variables. Read perlintro and you will learn about hashes (which you are already using but seem to not be using in all the places you should). Perl's symbol tables internally are implemented using hashes. If it works for Perl, it's certainly going to be good enough for you too. But even though it's a terrible use case, referring to variables using a variable is possible:

    $red = 1; $blue = 2; $green = 3; foreach $color (qw(red blue green)) { print "$color: $$color\n"; }

    But this is dangerous, bug prone, broken by design. Anywhere you feel you need to name a variable programatically, you need either a hash, an array, or a hard reference, which you can read about in perlref and perlreftut. Hashes and arrays are discussed in perlintro and perldata. Putting it all together is discussed in perldsc, perllol.

    Someone already linked to MJD's venerable trilogy of Usenet posts about why it's stupid to use a variable as a variable name. He was right 20 years ago when he posted that, and is still right. The road you are going down leads to unsolvable bugs that can only be fixed by complete rewrite.

    perlsub will discuss lexical variables. strict and warnings will discuss how to put the brakes on some forms of truly awful design decisions.

    Please take a few hours now learning to do it right rather than succumbing to the allure of getting it done quickly with limited understanding. Doing it right will be better for you in the longrun.

    There are legitimate uses for symbolic references. Those uses are very limited, and very narrow where they should be applied. Those uses should live buried deep in utility modules with nice clean user interfaces. Nobody should ever see them. If symbolic refs didn't even exist in Perl you, the happy programmer, would almost never even notice their absence.


    Dave