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

I have a situation were I run a certain command which prints to STDOUT. I capture this STDOUT in a buffer. The problem is that if the string captured in the buffer contains any symbols special to Perl, they are getting expanded, which I don't want to happen. I want to capture the string in the buffer in a literal mode. Is there some kind of syntax I can use to achieve this? If you suggest using single quotes to me, please demonstrate how, as I cannot see how it could possible fit in the sample code. Lastly I have my reasons for not wanting to use taint mode.
use strict; sub runCLIcommand { local *STDERR; my $lineSTDERR; my $returnValue = 0; open STDERR, '>', \$lineSTDERR; # This simulates what would in reality come from a command line in +terface. # In reality I would invoke: commands::display::ssh::run(); # which in turn would print to STDOUT. print "%dsadada ssadasd\n"; # Hash symbol does not cause a problem +, which I think is inconsistent? print "@dsadada sdsadasd\n"; # Problem !!!!!!!!!!!!!!!!!!!!!!!!!!! +!!!!!!!!!! print "$dsadada sdsadasd\n"; # Problem !!!!!!!!!!!!!!!!!!!!!!!!!!! +!!!!!!!!!! # Looks for these declarations: my @dsadada; my $dsadada; # Check that there was nothing written to STDERR, which implies # everything went alright. if (length($lineSTDERR) > 0) { $returnValue = 1; } return $returnValue; } sub processCLIoutput { my $array_ref = $_[0]; my @array = @$array_ref; for (my $i = 0; $i < @array; $i++) { $array[$i] =~ s/^\s*//; $array[$i] =~ s/\s*$//; # Not a neat solution plus, doesn't work in the simulation, # since the print command itself gets there first. $array[$i] =~ s/\$/DOLLAR/g; $array[$i] =~ s/\@/ARRAY/g; $array[$i] =~ s/\%/HASH/g; } return \@array; } sub getSshDetails { local *STDOUT; my @sshDetails = (); my @capturedSTDOUT; my $lineSTDOUT; my $array_ref; open STDOUT, '>', \$lineSTDOUT || die "Could not open STDOUT. $!"; # Anything that is printed to STDOUT from now on is captured in th +e buffer # $linesSTDOUT. Is there some kind of syntax I can use here that d +isables # variable expansion of the captured output??????????????????????? +????????????????????? if (runCLIcommand() != 0) { die "CLI command did not run successfully. \n"; } @capturedSTDOUT = split(/\n/, ($lineSTDOUT)); $array_ref = processCLIoutput(\@capturedSTDOUT); @sshDetails = @$array_ref; return \@sshDetails; } ################################################################### # main: ################################################################### my $array_ref = getSshDetails(); my @array = @$array_ref; for (my $i = 0; $i < @array; $i++) { print "Array entry: ". $i. "\t". $array[$i]. "\n"; }
PS: The above will not work unless you remove the '@' and '$' from the print statements. For some reason this is not a problem for the % symbol which, I find inconsistent. Surely the same attempt at variable expansion would apply to all the primitives.

Replies are listed 'Best First'.
Re: How do I disable variable expansion of strings?
by ikegami (Patriarch) on Sep 03, 2007 at 16:05 UTC
    Escape them.
    print "\@dsadada sdsadasd\n"; print "\$dsadada sdsadasd\n";

    Or use single-quotes instead of double-quotes (but single-quotes won't convert \n to a newline).

      Thank you for the suggestion, and it would be a valid one in a different context. It's my fault for not being more specific about what I want to do.

      The situation is:
      =================
      There are a set of commands implemented in Perl which make up a command line interface similar to the Bash prompt. Most of these commands display there output to STDOUT. I am attempting to wrap these commands with analogous subroutines in a Perl module, so that instead of printing to STDOUT, I capture a command's output, process it, and return meaningful values. Such a module is more reusable (and I have need of it).

      So you see I have to treat this command line interface as a blackbox, though it is possible, I am not 'permitted' to modify the strings that are spewed out when invoking a certain command.

      Finally even though I know about using backslashes and literals I don't know how to make use of them in the above code. Any other suggestions.

        The question I hear:

        I have a function that performs string interpolation. Without modifying the function, I want to prevent it from doing this interpolation.

        Either your question is unclear, or you might as well have asked

        I have a function that performs a loop. Without modifying the function, I want to prevent it from doing this loop.

        However, I'm pretty sure I'm understanding the problem incorrectly. Please provide more info. A minimal *representative* snippet would be ideal. The snippet you've already provided isn't representative of your problem.

        As mentioned, if you do not want the interpolation, escape the symbol...

        print "\%dsadada ssadasd\n"; print "\@dsadada sdsadasd\n"; print "\$dsadada sdsadasd\n";

        OR, use single quotes...

        print '%dsadada ssadasd' . "\n"; print '@dsadada sdsadasd' . "\n"; print '$dsadada sdsadasd' . "\n";

        Both of which will print:

        %dsadada ssadasd @dsadada sdsadasd $dsadada sdsadasd

        What exactly do you want it to print instead?

Re: How do I disable variable expansion of strings?
by moritz (Cardinal) on Sep 03, 2007 at 16:06 UTC
    It's called "interpolation", and it's a feature ;-)

    If you don't want interpolation, you should use single quotes around the strings, or escape the @ and $ with a backslash. Read perlintro for more information.

    print '$lalala @foobar'; # works print "\$lalala \@foobar"; # works as well print q{$lala @foobar}; # yet another method
      See previous response
Re: How do I disable variable expansion of strings?
by cdarke (Prior) on Sep 03, 2007 at 16:40 UTC
    "For some reason this is not a problem for the % symbol which, I find inconsistent."

    Hashes are not interpolated becuase they are not sequential objects. Using them in that way does not really make sense, although there are several work-arounds when you need it for debugging.

    "Surely the same attempt at variable expansion would apply to all the primitives."
    OK, except that a hash is not all that primitive. How would you expect a glob to be interpolated? The " operator can be overloaded, so you can change its behaviour if you need to. I get the feeling you need to read-up on interpolation, for example, in you main code:
    print "Array entry: ". $i. "\t". $array[$i]. "\n";
    Interpolated would be a bit nicer as:
    print "Array entry: $i\t$array[$i]\n";

      First you say it wouldn't be possible (Hashes are not interpolated becuase they are not sequential objects.), then you say it would be useless (Using them in that way does not really make sense). Both statements are false.

      The sequence changes when elements are added (or removed?), but that doesn't mean there isn't one. It would just as simple to support interpolation of hashes as it was to support interpolation of arrays.

      Some problems with implementing it at this point include backward compatibility and the possible resistance at adding another special variable (like $"), not a supposed lack of sequence.

      As for it being useless, that's untrue because I sometimes print the content of hashes without reordering them.

      Perl Hashes look sequential to me, they look exactly like a specialised array with the the condition that it contains an even number of entries.

      #my %var = ('k1' => 'v1', 'k2' => 'v2'); my %var = ('k1', 'v1', 'k2','v2'); print $var{k2}. "\n";
      I now what interpolation means in other contexts, I'm not sure in relation to hashes.

      As tempting as it is to use the some of the convenient shortcuts of Perl (and I am aware of the one you're suggesting), I prefer to use explicit notation in all languages as a rule of thumb, its safer, clearer, and avoids potentially unintended behavious.

      Defining what the primitives are for a particular language is irrelevant to my original question, so I won't pursue it.