Getopt::Long getting a string with spaces into a v

2019-02-19 15:34发布

问题:

I'm making a perl script which uses Getopt::Long to parse command line arguments. However, I have an argument which can accept a string (with spaces). How can I get the whole string into a variable. For example:

./script.pl --string=blah blah blah blah yup --another-opt

I need "blah blah blah blah yup" in variable $string. I know Getopt::Long supports multiple inputs for one argument when you know how many you will have (which I do not). Is this possible?

回答1:

You need to either put quotes around the argument:

./script.pl --string="blah blah blah blah yup" --another-opt

or escape the spaces:

./script.pl --string=blah\ blah\ blah\ blah\ yup --another-opt


回答2:

This is really a reply to MaxMackie's question on Ernest's answer, but it's too long, so here goes:

Your script never sees the quotes, only the shell that is passing the arguments. When you call a script (or program), what is happening on a lower level is that the command is called with several arguments in an array. The shell normally splits arguments up based on whitespace. What your program sees right now is:

[0]./script.pl
[1]--string=blah
[2]blah
[3]blah
[4]blah
[5]yup
[6]--another-opt

Putting quotes around the string or escaping it results in in this:

[0]./script.pl
[1]--string=blah blah blah blah yup
[2]--another-opt

Shells (bash in particular, others I'm sure) allows interspersing quotes without spaces as much as you like. ls -"l""h" is the same as ls -lh, hence you an do "--string=blah blah" or --string="blah blah". The parsing of the individual arguments with getopt that lets you put them out of order and use --long-name or -l happens after everything is turned into an array item and passed to the program. The shell has nothing to do with that.



回答3:

While I certainly agree that you should escape the arguments, if like me you have situation where you don't easily have control over the input then it is actually possible to do this with Getopt::Long.

Example: [https://www.jdoodle.com/a/oHG]

use strict;
use Getopt::Long qw(GetOptions);


my @spaces_string;

GetOptions('test=s{1,}' => \@spaces_string);
printf "String is: '%s'\n" ,join " ",@spaces_string;

You are defining your option as having 1 or more values, assign it to an array and then join it back into a string.

This is explained quite well under the 'Options with multiple values' section of the documentation: http://perldoc.perl.org/Getopt/Long.html#Options-with-multiple-values



回答4:

Now riddle me this... in the following scenario, I want to generate a quoted command-line argument via a shell command which then gets passed to a Perl script, like this:

script.pl `echo --string \"blah blah yup\"`

Trouble is, GetOptions ("string=s" => \$string) sets string's value to

"blah

containing the initial double-quote character and breaking at the first whitespace. The echo command by itself outputs the parameter with a quoted string that looks peachy:

--string "blah blah yup"

and if I call script.pl --string "blah blah yup" without the echo, the whitespace containing string gets set in the Perl script as expected.

I thought that maybe the backticks were the issue, but the same results ensue with these variants:

script.pl $(echo --string \"blah blah yup\")
script.pl $(echo "--string \"blah blah yup\"")
script.pl $(echo --string \"blah\ blah\ yup\")
script.pl $(echo '--string \"blah blah yup\"')

though that last example leads to string=\"blah (containing the initial backslash and double quote character).

Seems like the output returned from a shell command's STDOUT is not being handled the same way by Perl's argument parsing machinery as a string that is typed into the command-line. This apparent lack of string fungibility is somewhat surprising, but probably owing to some aspect of bash I don't understand. (Btw, I tested this with Perl 5.24 on Darwin and 5.16 on Linux)