Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

@ARGV ignores quotes

by ovedpo15 (Pilgrim)
on Jun 19, 2021 at 17:33 UTC ( [id://11134029]=perlquestion: print w/replies, xml ) Need Help??

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

Hello Monks!
I have script which uses GetOptions to parse options. My script allows the to use the --job option to pass everything the user wants (scripts, additional parameters, etc.). For example:
my_script.pl --option1 --option2 --job some_job.pl -option1 --option2 +--option3
My script runs the some_job.pl -option1 --option2 --option3 part at some point. ​Before the GetOptions parse, I have the following code:
my $job_flag = 0; foreach my $i (0..$#ARGV) { ​$opt{"job"} .= $ARGV[$i]." " if($job_flag); ​$job_flag = 1 if($ARGV[$i] =~ /^(\-\-|\-)job$/); ​undef $ARGV[$i] if($job_flag); }
The code just saves everything after --job into the $opt{job} and removes it from the ARGV so GetOptions won't parse it. Now I noticed that if there is quotes inside the job part, it will remove those quotes. For example:
my_script.pl --option1 --option2 --job some_job.pl -option1 'some_job2 +.pl -x abc' -option2
Then the Dumper of ARGS is:
$VAR1 = [ + + '--option1', '--option2', '--job', 'some_job.pl', '-option1', 'some_job2.pl -x abc', '-option2' ];
I would expect:
$VAR1 = [ + + '--option1', '--option2', '--job', 'some_job.pl', '-option1', '\'some_job2.pl -x abc\'', '-option2' ];
How can I know that there were quotes? I guess I'll need to think of another way to do this.

So there won't happen and X-Y problem, I'll explain what I'm trying to do. I want to get user's command and execute it at some point. It could have parameters and I don't want the user to insert it into file first. How can it be done?

2021-06-25 Athanasius fixed code tag.

Replies are listed 'Best First'.
Re: @ARGV ignores quotes (updated)
by AnomalousMonk (Archbishop) on Jun 19, 2021 at 17:56 UTC
    ... if there is quotes inside the job part, it will remove those quotes.

    Command line arguments are processed first by the command line interpreter (CLI) of the OS you're using, the "shell', e.g., sh, bash, etc. (I'm assuming you're running under *nix). It is the OS CLI that's "removing" quotes before Perl ever sees the command line arguments. E.g., your command line might have been
        my_script.pl '--option1' '--option2' '--job' 'some_job.pl' '-option1' 'some_job2.pl -x abc' '-option2'
    and the @ARGV dump from within Perl would have been exactly the same. (Update: For example, here's something from Windoze — I don't have access to *nix ATM:

    Win8 Strawberry 5.8.9.5 (32) Sat 06/19/2021 14:21:47 C:\@Work\Perl\monks >perl -MData::Dump -e "print qq{>$_< } for @ARGV" -- foo bar "baz \"ba +ff\" zip" >foo< >bar< >baz "baff" zip< Win8 Strawberry 5.8.9.5 (32) Sat 06/19/2021 14:23:37 C:\@Work\Perl\monks >perl -MData::Dump -e "print qq{>$_< } for @ARGV" -- "foo" "bar" "baz +\"baff\" zip" >foo< >bar< >baz "baff" zip<
    This even has escaped double-quotes embedded in one of the arguments. As you can see, the strings derived from the command line arguments are exactly the same within Perl.)

    Why do you need to know if a command line argument was originally quoted or not? (Update: IOW, why not just assume that all the command line options were quoted. What difference would it make?) This sounds very much like an XY problem.

    I want to get user's command and execute it at some point. It could have parameters and I don't want the user to insert it into file first.

    I don't understand what you are trying to do here and what problem you're trying to overcome.


    Give a man a fish:  <%-{-{-{-<

Re: @ARGV ignores quotes
by NetWallah (Canon) on Jun 19, 2021 at 18:55 UTC
    See this stackoverflow article for info on how to "embed" single quotes (bash disallows that, but the article has workarounds).

                    "The difficult we do today; the impossible takes a little longer."

Re: @ARGV ignores quotes
by hrcerq (Scribe) on Jun 19, 2021 at 21:37 UTC

    I hope I'm not saying anything stupid, but is &#8203; a subroutine call? If so, isn't this notation deprecated?

    return on_success() or die;

      G'day hrcerq,

      "I hope I'm not saying anything stupid, but is &#8203; a subroutine call?"

      There's certainly nothing "stupid" in your question. I was going to comment on that directly myself before scrolling down and seeing your post.

      The &#8203; is an HTML entity reference: a code which references a specific character. This is its decimal form. You may also see this in its hexadecimal form, &#x200b;, or as a named entity, &ZeroWidthSpace;. It is the Unicode® ZERO WIDTH SPACE (U+200B) character — the PDF code chart "General Punctuation Range: 2000–206F" has details; "Wikipedia: Zero-width space" has further discussion.

      How that got into the presented code — perhaps an artefact of a word processor used to write the code; maybe copied from an email; or whatever — is immaterial. The fact that the OP didn't check the Preview before posting (also note the obvious, broken <{line-break}/code> end tag) is of much more concern to me: what other problems exist in the code (not shown) that the OP may not have bothered to check either.

      "If so, isn't this notation deprecated?"

      The notation is not so much "deprecated" as syntactically incorrect. Note that the following did not need the strict or warnings pragmata for the compilation to be aborted.

      $ perl -e ' my $job_flag = 0; foreach my $i (0..$#ARGV) { &#8203;$opt{"job"} .= $ARGV[$i]." " if($job_flag); &#8203;$job_flag = 1 if($ARGV[$i] =~ /^(\-\-|\-)job$/); &#8203;undef $ARGV[$i] if($job_flag); } ' Number found where operator expected at -e line 4, near "&#8203" (Missing operator before 8203?) Number found where operator expected at -e line 5, near "&#8203" (Missing operator before 8203?) Number found where operator expected at -e line 6, near "&#8203" (Missing operator before 8203?) syntax error at -e line 4, near "&#8203" syntax error at -e line 5, near "&#8203" syntax error at -e line 6, near "&#8203" Execution of -e aborted due to compilation errors.

      The OP did not run this code!

      Updates: I had some issues with the title of this post; three versions tried; see "What are the formatting rules for the "Title" of posts?" for details. I'd also fixed a copy/paste error: the first line of the code I posted ($ perl -e ') was originally missing.

      — Ken

      Near as I can tell, &#8203; is a "ZERO WIDTH SPACE" HTML entity. I have no idea what it's doing there.


      Give a man a fish:  <%-{-{-{-<

Re: @ARGV ignores quotes
by Anonymous Monk on Jun 20, 2021 at 06:44 UTC
    I want to get user's command and execute it at some point.

    Is it supposed to be a shell command (a single string which may contain shell-special character combinations like &&), or an executable followed by an argument list, to be executed by system PROGRAM LIST with no processing by the shell?

    In the former case, any shell-special characters will be interpreted by the shell. In a way, you'd be introducing a shell injection vulnerability into your program. If the user passes types "echo hello world \`rm -rf whatever\`" as the command line argument, the string reaching the shell would be echo hello world `rm -rf whatever`, making the shell dutifully run rm -rf whatever before running echo hello world. Maybe that's what you want: after all, no security boundaries are crossed here, and the user is always able to rm -rf anything they want by typing the command instead of making your program do it.

    The downside is having to quote anything that might contain spaces, dollar signs, single and double quotes and everything else. If you want to supply a file name I'm eating in bed.ogg to mpv, you have to first quote it "I'm eating in bed.ogg", then quote the quotes: "mpv \"I'm eating in bed.ogg\"". There, now it's safe to pass to your program -- if it's intended to use the shell to run the command lines. Note that you can't use single quotes here because of escaping rules, but you could if the file name didn't contain an apostrophe. Add a few layers of that ("I need to pass this file name to a program that runs a command line that runs another command line..."), and therein lies madness.

    In the latter case, the arguments end up more or less directly passed to the execve system call, but they have to survive being an array of the arguments and not a single string. This way you can pass arbitrary NUL-terminated strings to the child process, no matter their contents, because a shell doesn't even come near them, so there's no danger in it interpreting `rm -rf whatever` and running it as a program, if you had a file named like that.

      See also The problem of "the" default shell.

      Alexander

      --
      Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)
Re: @ARGV ignores quotes
by ikegami (Patriarch) on Jun 20, 2021 at 06:11 UTC

    Just like the Perl code 'abc' produces the string abc, the shell code 'abc' produces the sequence abc. What you printed is literally what the shell passed to perl.

    To pass 'some_job2.pl -x abc', you could use

    \''some_job2.pl -x abc'\' "'"'some_job2.pl -x abc'"'" "'some_job2.pl -x abc'" \'some_job2.pl\ -x\ abc\' etc

    Seeking work! You can reach me at ikegami@adaelis.com

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11134029]
Approved by davies
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others wandering the Monastery: (4)
As of 2024-04-19 17:27 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found