in reply to Re: backticks execution "inside" variable (string)
in thread backticks execution "inside" variable (string)

Thank you, Ken!

About the first half, my response to this answer also applies, with one exception, that I didn't know [3..5] construct, thank you for that specifically, enriched me by that knowledge.

But the second is much closer to what I am looking for. Actually I was thinking about splitting and partial evaluation, but I was curious, if there is something yet simpler, what will replace all occurences (theoretically there can be more of them, although currently are not) of backticks pairs with standard output of their contents. I am able to code something like you provided (I don't want to abuse you guys to code that instead of me), this is not the problem, but I prefer re-using already existing functionalities instead of enlarging code base with functionalities, which are already avaliable from some module or built-in construct.

Replies are listed 'Best First'.
Re^3: backticks execution "inside" variable (string)
by kcott (Archbishop) on Dec 21, 2019 at 06:57 UTC
    "... I didn't know [3..5] construct, thank you for that specifically, enriched me by that knowledge."

    You're welcome. I see ++haukex has commented on that construct — I've nothing further to add unless you have questions about it.

    "... but I was curious, if there is something yet simpler, what will replace all occurences ..."

    Personally, I still think your approach to this is questionable; I'll discuss that in more detail further down. One standard way to do multiple replacements is with a substitution using the 'g' modifier (s///g). So, this would achieve what you're questionably asking for:

    $ perl -E ' my $x = $ARGV[0] =~ s/(`[^`]+`)/$1/eegr =~ s/\R//gr; say $x; ' 'DMY_`date +%d%m%Y`_MY_`date +%m%Y`_Y_`date +%Y`.log' DMY_21122019_MY_122019_Y_2019.log

    Note that say and \R became available in v5.10 and the 'r' modifier in v5.14. Depending on your Perl version, you might need something like:

    $ perl -e ' my $x = $ARGV[0]; $x =~ s/(`[^`]+`)/chomp(my $y = eval $1); $y/eg; print "$x\n"; ' 'DMY_`date +%d%m%Y`_MY_`date +%m%Y`_Y_`date +%Y`.log' DMY_21122019_MY_122019_Y_2019.log

    Important: Please be very aware that I am not recommending this approach; I'm merely advising of options.

    The security issues have already been pointed out. In my opinion, it's just far too easy for some bad command to become embedded in your filenames. This could be accidental — a simple typo by your good self — or malicious; however, that's completely immaterial. The fact that it could happen should be sufficient to steer you away from this course of action.

    I would suggest you create a module which does all the work for you and contains tokens representing only those commands that you choose to allow. I would also pick something other than backticks to delimit the command tokens; in the following, I've used tildes as an example alternative but pick whatever you like (it doesn't need to be a single character).

    Here's a rough example of what that module might look like. I've continued using localtime purely for consistency with previous example code I provided; I see lots of alternative suggestions in this thread — pick whatever you want.

    package Pm_11110263_FilenameGen; use strict; use warnings; use Exporter 'import'; our @EXPORT_OK = qw{gen_filename}; my %dispatch = ( 'DATE DMY' => sub { my ($d, $m, $y) = (localtime)[3..5]; return join '', $d, $m+1, $y+1900; }, 'DATE MY' => sub { my ($m, $y) = (localtime)[4,5]; return join '', $m+1, $y+1900; }, 'DATE Y' => sub { return (localtime)[5] + 1900; }, ); sub _perform_substitution { my ($token) = @_; die "FATAL! '$token' is invalid" unless exists $dispatch{$token}; return $dispatch{$token}->(); } sub gen_filename { my ($template) = @_; $template =~ s/~([^~]+)~/_perform_substitution($1)/eg; return $template; } 1;

    Now you only need to use that module and call gen_filename():

    $ perl -E ' use lib "."; use Pm_11110263_FilenameGen "gen_filename"; say gen_filename($ARGV[0]); ' 'daily_~DATE DMY~_monthly_~DATE MY~_yearly_~DATE Y~.log' daily_21122019_monthly_122019_yearly_2019.log

    The 'use lib ".";' is only there because, for demo purposes, I put "Pm_11110263_FilenameGen.pm" in the current working directory. So, after a proper installation of the module, you'd only need two lines of code.

    And if someone (accidentally or maliciously) tried something bad, no harm would be done.

    $ perl -E ' use lib "."; use Pm_11110263_FilenameGen "gen_filename"; say gen_filename($ARGV[0]); ' 'daily_~DATE DMY~_monthly_~DATE MY~_yearly_~DATE Y~_BAD_~RM ROOT~.lo +g' FATAL! 'RM ROOT' is invalid at Pm_11110263_FilenameGen.pm line 26.

    — Ken

    A reply falls below the community's threshold of quality. You may see it by logging in.
Re^3: backticks execution "inside" variable (string)
by haukex (Archbishop) on Dec 20, 2019 at 18:53 UTC
    I didn't know [3..5] construct

    kcott's (localtime)[3..5] is a range operator used in a list slice.

    if there is something yet simpler, what will replace all occurences (theoretically there can be more of them, although currently are not) of backticks pairs with standard output of their contents

    I'm still unclear on what syntax you want to use here - the shell's, Perl's, or something custom? In bash's syntax, "X`date`Y" will interpolate, while in Perl's syntax it won't. And the shell quoting rules can get pretty tricky, for example "X`echo \\\``Y""1"'2' will evaluate to X`Y12.

    Perhaps you could show several representative samples of the kinds of strings you want to interpolate, with some complex examples mixed in?