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

Hi, I am having some trouble passing a variable as a command line argument to a script. I have a perl script in which I am trying to invoke a shell script by passing a commnad line argument.
`test.sh "$string"`;
The problem is that in case if $string contains characters like $ or @ or % then these values are getting replaced by the perl keys. for example if $string is abc$ds then the value being passed is abcs. The value of $d is being getting replaced. I am baffled like how are we going to pass this variable. Please suggest Thnanx in advance

Replies are listed 'Best First'.
Re: passing a command line argument
by bart (Canon) on Oct 04, 2007 at 11:34 UTC
    The problem is that in case if $string contains characters like $ or @ or % then these values are getting replaced by the perl keys.
    No it doesn't.

    "Interpolation", as it's called, goes only one level deep. Hence, it's the string contents of the variable $string that is inserted in the command line. Contrary to what you seem to believe, nothing else is replaced.

    And %hash is never interpolated in a string. Never.

    What may happen is that the invoked shell may treat shell metacharacters in this command line special (for example, replace parts of the command line by environment variables). But that's not Perl's fault. That's why $d may appear to disappear from your command line.

    Use of String::ShellQuote may help you in alleviating that problem.

      Alternately use the LIST form of system yourself directly (or IPC::Run if you need the output from the subprocess) and take any intermediary shell out of the picture to begin with and you won't need to worry about quoting.

      my $test_sh_ret = system( "test.sh", $string );
Re: passing a command line argument
by jettero (Monsignor) on Oct 04, 2007 at 12:01 UTC

    bart is correct, but special shell quoting modules may be overkill. I think you can probably get away with the multi argument version of system iff you don't need the output to come back from the qx.

    You can also open my $in, "-|", qw(program), "$sting" or die $! to get the output and use the multi-arg pipe. Huzzah.

    -Paul

Re: passing a command line argument
by mwah (Hermit) on Oct 04, 2007 at 13:07 UTC
    s_gaurav1091I am baffled like how are we going to pass this variable

    It might be necessary to mask "variables names" against beeing
    evaluated by shell invocation, this is one case where it might
    happen:
    ... my $PATH = "!please don't show this!"; my $command = 'echo test.sh'; my $args = "\\\$PATH is a name"; # try: "\$PATH is a name"; print "args: ", $args, "\n"; print "dummy: ", $PATH,"\n"; my $output = qx{ $command $args }; # use qx for backticks! print "\ncommand line echo: ", $output, "\n"; ...
    If you don't mask the $PATH, the output will suprise you ;-)
    (This has been said already but I tried to give a "hands on" example.)

    Regards

    mwa
Re: passing a command line argument
by naikonta (Curate) on Oct 04, 2007 at 16:17 UTC
    As bart points out, it can't happen. It could be the shell that trying to replace what it considers special (meta) characters in the $string. You can use quotemeta to escape those characters or using the equivalent escape sequences such as \Q.
    $ ls hello $ perl -e 'my $dir = q(not$socooldir); system "mkdir $dir" and die "ex +ecution failed\n"' $ ls hello not $ perl -e 'my $dir = q(not$socooldir); $dir = quotemeta $dir; system " +mkdir $dir" and die "execution failed\n"' $ ls hello not not$socooldir $ perl -e 'my $dir = q(not$socooldir); system "mkdir \Q$dir" and die " +execution failed\n"' mkdir: cannot create directory `not$socooldir': File exists execution failed

    Of course, perl has its own mkdir function, internally. Please note that the third execution fails because directory already exists, indicating that \Q$dir and quotemeta $dir result in the same directory name.

    One more thing, please don't use `shellcmd args` in void context, because you ask for something to return but effectively discard it. Assign it to a scalar or an array to capture the output if you want it so.

    my @lines = `shellcmd args`; # list context my $line = `shellcmd args`; # scalar context

    Open source softwares? Share and enjoy. Make profit from them if you can. Yet, share and enjoy!