tags:

views:

102

answers:

3

Say I have an environment variable myvar:

myvar=\tapple\n

When the following command will print out this variable

perl -e 'print "$ENV{myvar}"'

I will literally have \tapple\n, however, I want those control chars to be evaluated and not escaped. How would I achieve it?

In the real world $ENV residing in substitution, but I hope the answer will cover that.

+1  A: 

Use eval:

perl -e 'print eval qq{"$ENV{myvar}"}' 

UPD: You can also use substitution with the ee switch, which is safer:

perl -e '(my $s = $ENV{myvar}) =~ s/(\\n|\\t)/"qq{$1}"/gee; print $s'
eugene y
Evaluating code direct from an environment variable? Sounds like a security risk.
rjh
It is a bit risky, but it seems like it's the answer for what Michael needed.
modz0r
Don't do this. The string eval is often the sign that you need to learn more Perl. :)
brian d foy
@brian d foy: not really. If you want to evaluate something exactly according to Perl's rules, `eval` is more likely to be correct than implementing it manually. On the other hand, `eval` does a lot more than just translate "\t" to tabs -- it can also delete files :)
jrockway
Well, eval can be correct if you know what you are doing, but that doesn't change my statement at all. Most times you still see a string eval, it's not correct, meaning it does what you want without doing what you don't want (or don't know about). Just because you know how to use it properly doesn't negate "most" or "often". :)
brian d foy
+2  A: 

You should probably be using String::Escape.

use String::Escape qw(unbackslash);

my $var = unbackslash($ENV{'myvar'});

unbackslash unescapes any string escape sequences it finds, turning them into the characters they represent. If you want to explicitly only translate \n and \t, you'll probably have to do it yourself with a substitution as in this answer.

darch
My only concern here is that `unprintable` might translate much more than you are willing to accept.
brian d foy
That's a good point. Lemme reflect that...
darch
This answer sounds like the opposite of what he wants to do. "I want those control chars to be evaluated and not escaped," he writes. So it seems like "unbackslash" is the function he wants from that module.
jrockway
Inaccurate; `unprintable` is one of the evaluation functions. That said, I'll take your advice and the perldoc's and recommend `unbackslash`.
darch
+1  A: 

There's nothing particularly special about a sequence of characters that includes a \. If you want to substitute one sequence of characters for another, it's very simple to do in Perl:

my %sequences = (
      '\\t' => "\t",
      '\\n' => "\n",
      'foo' => 'bar',
      );

 my $string = '\\tstring fool string\\tfoo\\n';

 print "Before: [$string]\n";
 $string =~ s/\Q$_/$sequences{$_}/g for ( keys %sequences );
 print "After: [$string]\n";

The only trick with \ is to keep track of the times when Perl thinks it's an escape character.

Before: [\tstring fool string\tfoo\n]
After: [    string barl string  bar
]

However, as darch notes, you might just be able to use String::Escape.

Note that you have to be extremely careful when you're taking values from environment variables. I'd be reluctant to use String::Escape since it might process quite a bit more than you are willing to translate. The safe way is to only expand the particular values you explicitly want to allow. See my "Secure Programming Techniques" chapter in Mastering Perl where I talk about this, along with the taint checking you might want to use in this case.

brian d foy