double eval?

Discussion in 'Perl Misc' started by bettyann, Jul 18, 2004.

  1. bettyann

    bettyann Guest

    i have an input file, Icons.lis, like so:

    #--------------
    # line starting with "%" is an executable perl command

    % $zyxDir = "/System/Library/CoreServices/SystemIcons.bundle/Contents/Resources";
    % $cbaDir = "/Users/bettyann/icons/03-08-04_Bubbly-System";

    # System Icon Files # Local Icon File
    $zyxDir/ApplicationsFolderIcon.icns $cbaDir/older-applications
    $zyxDir/CDAudioVolumeIcon.icns $cbaDir/cd
    #--------------

    how do i get perl to interpret the variable "$zyxDir" and "$cbaDir" in
    the filenames (in the last two lines of the above input file)? i can
    evaluate the "%" command just fine but i cannot resolve/ interpret/
    expand the filenames. in other words, how do i get the first
    filename, $zyxDir/ApplicationsFolderIcon.icns, to resolve to
    /System/Library/CoreServices/SystemIcons.bundle/Contents/Resources/ApplicationsFolderIcon.icns?

    my code:

    #!/usr/bin/perl
    # open the list file
    $listFile = "Icons.lis";
    open( FID, "< $listFile" ) || die "Could not open $listFile for
    reading.";
    while(<FID>){ # Read line by line
    # skip blanks and comment lines
    s/#.*//; # ignore comments by erasing them
    next if /^(\s)*$/; # skip blank lines
    chomp; # remove trailing newline characters
    if ( s/^%// ) {
    # this is an executable perl command
    print "eval >>$_<< \n";
    eval( $_ ); # debug
    next;
    }
    # debug - these variables are defined from above "eval"
    print "\n";
    print "zyxDir >>$zyxDir<< \n";
    print "cbaDir >>$cbaDir<< \n";
    # get the two filenames from this line
    ( $sysIcns, $newIcon ) = split;
    print "sysIcns >>$sysIcns<< \n";
    print "newIcon >>$newIcon<< \n";
    `ls $sysIcns`;
    } # while( <FID>)
    close( FID );

    i get this output and error:

    eval >> $zyxDir = "/System/Library/CoreServices/SystemIcons.bundle/Contents/Resources";<<
    eval >> $cbaDir = "/Users/bettyann/icons/03-08-04_Bubbly-System";<<

    zyxDir >>/System/Library/CoreServices/SystemIcons.bundle/Contents/Resources<<
    cbaDir >>/Users/bettyann/icons/03-08-04_Bubbly-System<<
    sysIcns >>$zyxDir/ApplicationsFolderIcon.icns<<
    newIcon >>$cbaDir/folder-applications<<
    ls: /ApplicationsFolderIcon.icns: No such file or directory

    the error is presumably because the "$zyxDir" in $sysIcns is not
    evaluated. i tried a number of eval combinations ... with no success.

    thanks - bettyann
    bettyann, Jul 18, 2004
    #1
    1. Advertising

  2. bettyann wrote:
    > i have an input file, Icons.lis, like so:
    >
    > #--------------
    > # line starting with "%" is an executable perl command
    >
    > % $zyxDir = "/System/Library/CoreServices/SystemIcons.bundle/Contents/Resources";
    > % $cbaDir = "/Users/bettyann/icons/03-08-04_Bubbly-System";
    >
    > # System Icon Files # Local Icon File
    > $zyxDir/ApplicationsFolderIcon.icns $cbaDir/older-applications
    > $zyxDir/CDAudioVolumeIcon.icns $cbaDir/cd
    > #--------------
    >
    > how do i get perl to interpret the variable "$zyxDir" and "$cbaDir"
    > in the filenames (in the last two lines of the above input file)?


    You are asking a FAQ.

    perldoc -q "expand variables"

    You can follow one of the suggestions in the FAQ answer. However, a
    more secure method is to do plain substitutions:

    $sysIcns =~ s/\$zyxDir/$zyxDir/;

    <snip>

    > my code:
    >
    > #!/usr/bin/perl


    Where are

    use strict;
    use warnings;

    ??

    --
    Gunnar Hjalmarsson
    Email: http://www.gunnar.cc/cgi-bin/contact.pl
    Gunnar Hjalmarsson, Jul 19, 2004
    #2
    1. Advertising

  3. bettyann

    Bob Walton Guest

    bettyann wrote:

    > i have an input file, Icons.lis, like so:
    >
    > #--------------
    > # line starting with "%" is an executable perl command
    >
    > % $zyxDir = "/System/Library/CoreServices/SystemIcons.bundle/Contents/Resources";
    > % $cbaDir = "/Users/bettyann/icons/03-08-04_Bubbly-System";
    >
    > # System Icon Files # Local Icon File
    > $zyxDir/ApplicationsFolderIcon.icns $cbaDir/older-applications
    > $zyxDir/CDAudioVolumeIcon.icns $cbaDir/cd
    > #--------------
    >
    > how do i get perl to interpret the variable "$zyxDir" and "$cbaDir" in
    > the filenames (in the last two lines of the above input file)? i can
    > evaluate the "%" command just fine but i cannot resolve/ interpret/
    > expand the filenames. in other words, how do i get the first
    > filename, $zyxDir/ApplicationsFolderIcon.icns, to resolve to
    > /System/Library/CoreServices/SystemIcons.bundle/Contents/Resources/ApplicationsFolderIcon.icns?



    ....


    > thanks - bettyann
    >


    Well, besides being a FAQ (see perldoc -q variables), what you are doing
    is generally a *bad idea*. You are assigning to variable names you are
    reading from an input file. If your input file is totally under your
    control and no one else ever prepares any of it, you might argue that
    you're OK, but in general this is a huge no-no. Consider that *any*
    variable name could be specified -- consider what could happen if
    someone put the variable $sysIcns in the input. Also, you must consider
    the effects of input like:

    % system('rm -f /');

    to your scheme. In addition, consider what the backticks could do with
    a filename given like:

    % $xxx = "Some/nice/path;rm -f /;";

    You should never execute a command on your system unless you have
    verified it doesn't contain stuff like that.

    So what should you do?

    1. In this case, you could simply parse the "%" lines and put the
    result in a hash. That way, no matter what kind of crap they contain,
    they won't trash your system or pollute your namespace. Something like:

    s/%\s+\$(\w+)\s*=\s*"(.*?)"\s*;/$hash{$1}=$2/e;

    2. Then when you want to "interpolate" the "variable" into a "string",
    you could use something like:

    $sysIcns=~s/\$(\w+)/$hash{$1}/g;

    3. Validate the string passed to the ls command in the backticks
    operator so you know it won't do anything nasty.

    Here is a complete example which may be copy/paste/executed:

    #!/usr/bin/perl
    use strict;
    use warnings;
    use Data::Dumper;
    my %hash;
    my $sysIcns;
    my $newIcon;
    while(<DATA>){ # Read line by line
    # skip blanks and comment lines
    s/#.*//; # ignore comments by erasing them
    next if /^(\s)*$/; # skip blank lines
    chomp; # remove trailing newline characters
    if ( s/^%// ) {
    # this is an executable perl command
    print "eval >>$_<< \n";
    #eval( $_ ); # debug
    s/\s*\$(\w+)\s*=\s*"(.*?)"\s*;/$hash{$1}=$2/e;
    next;
    }
    # debug - these variables are defined from above "eval"
    print "\n";
    print Dumper(\%hash);
    # print "zyxDir >>$zyxDir<< \n";
    # print "cbaDir >>$cbaDir<< \n";
    # get the two filenames from this line
    ( $sysIcns, $newIcon ) = split;
    #$sysIcns=eval "\"$sysIcns\""; <-- (what you would have needed)
    #$newIcon=eval "\"$newIcon\"";
    $sysIcns=~s/\$(\w+)/$hash{$1}/g;
    $newIcon=~s/\$(\w+)/$hash{$1}/g;
    print "sysIcns >>$sysIcns<< \n";
    print "newIcon >>$newIcon<< \n";
    `ls $sysIcns` if $sysIcns=~m!^[/\w.-]+$!; #validate
    } # while( <FID>)
    #close( FID );
    close( DATA );
    __END__
    #--------------
    # line starting with "%" is an executable perl command

    #stuff removed from next line so it doesn't wrap
    % $zyxDir = "/System/SystemIcons.bundle/Contents/Resources";
    % $cbaDir = "/Users/bettyann/icons/03-08-04_Bubbly-System";

    # System Icon Files # Local Icon File
    $zyxDir/ApplicationsFolderIcon.icns $cbaDir/older-applications
    $zyxDir/CDAudioVolumeIcon.icns $cbaDir/cd
    #--------------

    --
    Bob Walton
    Email: http://bwalton.com/cgi-bin/emailbob.pl
    Bob Walton, Jul 19, 2004
    #3
  4. bettyann

    Joe Smith Guest

    bettyann wrote:

    > eval >> $cbaDir = "/Users/bettyann/icons/03-08-04_Bubbly-System";<<


    If the contents of $cbaDIR was "FOOBAR" before the eval, then the
    eval would be interpreted as
    FOOBAR = "/Users/bettyann/icons/03-08-04_Bubbly-System";
    because there was no backslash in front of the $ in $cbaDIR.

    Take the advice of the other posters in this thread, or look at
    http://search.cpan.org/search?query=config file for better ways.
    -Joe
    Joe Smith, Jul 19, 2004
    #4
  5. Joe Smith wrote:
    > bettyann wrote:
    >> eval >> $cbaDir = "/Users/bettyann/icons/03-08-04_Bubbly-System";<<

    >
    > If the contents of $cbaDIR was "FOOBAR" before the eval, then the
    > eval would be interpreted as
    > FOOBAR = "/Users/bettyann/icons/03-08-04_Bubbly-System";
    > because there was no backslash in front of the $ in $cbaDIR.


    No, it wouldn't. The above is a result of

    print "eval >>$_<< \n";

    in the while loop, and the variabel name in the $_ string is not
    interpolated.

    > Take the advice of the other posters in this thread, or look at
    > http://search.cpan.org/search?query=config file for better ways.


    Concur.

    --
    Gunnar Hjalmarsson
    Email: http://www.gunnar.cc/cgi-bin/contact.pl
    Gunnar Hjalmarsson, Jul 19, 2004
    #5
  6. bettyann

    bettyann Guest

    thanks bob + all,

    > You are asking a FAQ.
    >
    > perldoc -q "expand variables"


    this is the frustrating thing for me ... i didn't know what to search
    for in perldoc. it's hard to know what you don't know.

    > what you are doing is generally a *bad idea*.


    yes, thank you for pointing that out. this little script is for my
    own "personal" use -- just for housekeeping. but, in the interest of
    learning new things, i am taking your advice and will not implement
    this *bad idea* ;)

    > 1. In this case, you could simply parse the "%" lines and put the
    > result in a hash. That way, no matter what kind of crap they contain,
    > they won't trash your system or pollute your namespace. Something like:
    >
    > s/%\s+\$(\w+)\s*=\s*"(.*?)"\s*;/$hash{$1}=$2/e;


    nice. if i understand correctly, i'm building my own "dictionary"
    where $1 is the variable name and $2 is its 'definition'.

    > 2. Then when you want to "interpolate" the "variable" into a "string",
    > you could use something like:
    >
    > $sysIcns=~s/\$(\w+)/$hash{$1}/g;


    and then i use my little ol' "dictionary" to substitute.

    > 3. Validate the string passed to the ls command in the backticks
    > operator so you know it won't do anything nasty.


    this is the part i don't understand well. i'm trying to understand
    the m// command:

    > `ls $sysIcns` if $sysIcns=~m!^[/\w.-]+$!; #validate


    (i feel as if i am back in my high school french class where i can
    figure out a few individual words but cannot really get the grammar
    and hence the big-picture.) i think the m// command is saying:

    match beginning of line
    all the things in this class [...]
    the class is made up of: forward-slash, word, any-char, dash
    match this class one-or-more times (i thought just one-time, {1}, made
    sense)
    match end of line

    i don't understand how this 'validates' a safe command/string.

    > while(<DATA>){ # Read line by line

    [snip]
    > } # while( <DATA>)
    > close( DATA );
    > __END__
    > #--------------
    > # line starting with "%" is an executable perl command
    >
    > #stuff removed from next line so it doesn't wrap
    > % $zyxDir = "/System/SystemIcons.bundle/Contents/Resources";
    > % $cbaDir = "/Users/bettyann/icons/03-08-04_Bubbly-System";
    >
    > # System Icon Files # Local Icon File
    > $zyxDir/ApplicationsFolderIcon.icns $cbaDir/older-applications
    > $zyxDir/CDAudioVolumeIcon.icns $cbaDir/cd
    > #--------------


    this is cool!

    thanks, i got this script going. i look forward to understanding the
    m// expression better, tho.
    bettyann, Jul 19, 2004
    #6
  7. Using the FAQ [was: double eval?]

    bettyann wrote:
    > Gunnar Hjalmarsson wrote:
    >> You are asking a FAQ.
    >>
    >> perldoc -q "expand variables"

    >
    > this is the frustrating thing for me ... i didn't know what to
    > search for in perldoc. it's hard to know what you don't know.


    Yep. That's why I pointed you to it.

    OTOH, you are expected to make a try before posting a question here.
    And, actually, it's not that difficult. Personally I like to browse
    the Perl docs. One place where the FAQ is available in HTML format is
    http://www.perldoc.com/perl5.8.4/pod/perlfaq.html

    --
    Gunnar Hjalmarsson
    Email: http://www.gunnar.cc/cgi-bin/contact.pl
    Gunnar Hjalmarsson, Jul 20, 2004
    #7
  8. bettyann

    Bob Walton Guest

    bettyann wrote:

    > thanks bob + all,

    ....
    >> `ls $sysIcns` if $sysIcns=~m!^[/\w.-]+$!; #validate
    >>

    >
    > (i feel as if i am back in my high school french class where i can
    > figure out a few individual words but cannot really get the grammar
    > and hence the big-picture.) i think the m// command is saying:
    >
    > match beginning of line
    > all the things in this class [...]
    > the class is made up of: forward-slash, word, any-char, dash


    -------------------------------------------------^^^^^^^^
    In a character class, . stands for itself, as does almost every other
    character other than \ and those escaped by it, and - not at the
    beginning or end, and ... well, read up on the rules for character
    classes in "perldoc perlre". It's a bit complicated. Anyway, the
    repeated character class will match any string containing only
    characters among letters, digits, underscore, period, hyphen, and
    forward-slash. It will fail to match any string containing any other
    character, including one containing a ; . Also, the character class
    will not match whitespace, which also disallows "rm -f /" or any other
    shell command requiring whitespace.


    > match this class one-or-more times (i thought just one-time, {1}, made
    > sense)



    No, we want to match *every* character in the string. That's why the ^
    to force the match to start at the start of the string, the repeated
    character class, and the $ to force the match to end at the end of the
    string. Then, if there is any character in the string which is not
    matched by the character class, the match will fail. m!...! was used to
    avoid possible issues quoting the / default regexp delimiter (I can't
    remember if a delimiter has to be quoted inside a character class or
    not, and I'm to lazy to look it up).


    > match end of line
    >
    > i don't understand how this 'validates' a safe command/string.



    Well, in the specific example given ("blah/blah/blah;rm -f /;"), it will
    not match because the string being given to ls contains a semicolon
    (typically the shell's character to separate multiple commands on a
    single line). Without a ; everything will be an argument to ls, and not
    much harm can come from that. It also will fail to match the whitespace
    in the "rm -f /" command. The principle which was used in constructing
    the validation expression was to specifically include all characters
    which are desired to be permitted, and to exclude all others. This is
    better than trying to specifically exclude those you don't want --
    you're likely to forget one or more, leading to an insecure script. For
    example, what about "blah/blah|rm -f /"? Are there more? Maybe? The
    character class listed will match all your examples -- depending on the
    file names, though, something else may be required. An even better idea
    would be to use something else to list your files besides a system
    command, perhaps the stat() function. That way, you can't inadvertently
    pass bad stuff to a shell, since there isn't any shell involved.

    HTH.

    ....

    --
    Bob Walton
    Email: http://bwalton.com/cgi-bin/emailbob.pl
    Bob Walton, Jul 20, 2004
    #8
  9. bettyann

    krakle Guest

    Gunnar Hjalmarsson <> wrote in message news:<>...
    > bettyann wrote:
    > > i have an input file, Icons.lis, like so:
    > >
    > > #--------------
    > > # line starting with "%" is an executable perl command
    > >
    > > % $zyxDir = "/System/Library/CoreServices/SystemIcons.bundle/Contents/Resources";
    > > % $cbaDir = "/Users/bettyann/icons/03-08-04_Bubbly-System";
    > >
    > > # System Icon Files # Local Icon File
    > > $zyxDir/ApplicationsFolderIcon.icns $cbaDir/older-applications
    > > $zyxDir/CDAudioVolumeIcon.icns $cbaDir/cd
    > > #--------------
    > >
    > > how do i get perl to interpret the variable "$zyxDir" and "$cbaDir"
    > > in the filenames (in the last two lines of the above input file)?

    >
    > You are asking a FAQ.
    >
    > perldoc -q "expand variables"
    >
    > You can follow one of the suggestions in the FAQ answer. However, a
    > more secure method is to do plain substitutions:
    >
    > $sysIcns =~ s/\$zyxDir/$zyxDir/;
    >
    > <snip>
    >
    > > my code:
    > >
    > > #!/usr/bin/perl

    >
    > Where are
    >
    > use strict;
    > use warnings;
    >
    > ??


    and -Tw
    krakle, Jul 20, 2004
    #9
  10. bettyann

    Ben Morrow Guest

    Quoth (bettyann):
    > > 3. Validate the string passed to the ls command in the backticks
    > > operator so you know it won't do anything nasty.

    >
    > this is the part i don't understand well. i'm trying to understand
    > the m// command:
    >
    > > `ls $sysIcns` if $sysIcns=~m!^[/\w.-]+$!; #validate

    >
    > (i feel as if i am back in my high school french class where i can
    > figure out a few individual words but cannot really get the grammar
    > and hence the big-picture.) i think the m// command is saying:
    >
    > match beginning of line
    > all the things in this class [...]
    > the class is made up of: forward-slash, word, any-char, dash
    > match this class one-or-more times (i thought just one-time, {1}, made
    > sense)
    > match end of line
    >
    > i don't understand how this 'validates' a safe command/string.


    The point here is that the ^ and the $ make sure that the string doesn't
    contain anything *but* /\w.-: for instance, it isn't '; rm -rf ~'.

    Note that there is no need to use ls here at all: it would be faster to
    use opendir/readdir.

    Ben

    --
    All persons, living or dead, are entirely coincidental.
    Kurt Vonnegut
    Ben Morrow, Jul 20, 2004
    #10
  11. bettyann

    bettyann Guest

    Re: Using the FAQ [was: double eval?]

    > >> You are asking a FAQ.
    > >>
    > >> perldoc -q "expand variables"

    > >
    > > this is the frustrating thing for me ... i didn't know what to
    > > search for in perldoc. it's hard to know what you don't know.

    >
    > Yep. That's why I pointed you to it.


    yes, thank you.

    > OTOH, you are expected to make a try before posting a question here.
    > And, actually, it's not that difficult. Personally I like to browse
    > the Perl docs. One place where the FAQ is available in HTML format is
    > http://www.perldoc.com/perl5.8.4/pod/perlfaq.html


    actually, gunnar, i did make the effort. and a rather big effort,
    too. as i say, it is hard to know what you don't know. i kept
    searching for things like "eval" which is a tcl command/concept. as
    you can guess, searching "substitute" comes up with all sorts of stuff
    .... not relevant to what i was looking for.

    thanks for your help. i appreciate it.
    bettyann, Jul 20, 2004
    #11
  12. bettyann

    bettyann Guest

    bob + ben,

    thanks. now that i understand *what* we're matching (basically, a
    filename that cannot contain [space], et al), i better understand
    *how* you did it.

    thanks for all your help. i do appreciate your efforts.
    - bettyann
    bettyann, Jul 26, 2004
    #12
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Eric Newton
    Replies:
    3
    Views:
    9,330
    Brock Allen
    Apr 4, 2005
  2. Sydex
    Replies:
    12
    Views:
    6,425
    Victor Bazarov
    Feb 17, 2005
  3. DataBinder.Eval and Eval.

    , Jun 16, 2006, in forum: ASP .Net
    Replies:
    1
    Views:
    513
    Karl Seguin [MVP]
    Jun 16, 2006
  4. Alex van der Spek

    eval('07') works, eval('08') fails, why?

    Alex van der Spek, Jan 8, 2009, in forum: Python
    Replies:
    6
    Views:
    1,380
    Bruno Desthuilliers
    Jan 8, 2009
  5. Liang Wang
    Replies:
    8
    Views:
    116
    Ben Morrow
    Feb 2, 2008
Loading...

Share This Page