Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

After using PHP's getopt(), how can I tell what arguments remain?

Tags:

php

getopt

OK, So PHP has a built-in getopt() function which returns information about what program options the user has provided. Only, unless I'm missing something, it's completely borked! From the manual:

The parsing of options will end at the first non-option found, anything that follows is discarded.

So getopt() returns an array with the valid and parsed options only. You can still see the entire original command-line by looking at $argv, which remains unmodified, but how do you tell where in that command-line getopt() stopped parsing arguments? It is essential to know this if you want treat the remainder of a command-line as other stuff (like, e.g., file names).

Here's an example...

Suppose I want to set up a script to accept the following arguments:

Usage: test [OPTION]... [FILE]...  Options:   -a  something   -b  something   -c  something 

Then I might call getopt() like this:

$args = getopt( 'abc' ); 

And, if I ran the script like this:

$ ./test.php -a -bccc file1 file2 file3 

I should expect to have the following array returned to me:

Array (     [a] =>     [b] =>     [c] => Array         (             [0] =>             [1] =>             [2] =>         ) ) 

So the question is this: How on Earth am I supposed to know that the three unparsed, non-option FILE arguments start at $argv[ 3 ]???

like image 322
edam Avatar asked Oct 03 '13 12:10

edam


People also ask

Does getopt change argv?

This behavior is a GNU extension, not available with libraries before glibc 2. By default, getopt() permutes the contents of argv as it scans, so that eventually all the nonoptions are at the end.

What does the getopt function return when there is no more work to do?

The getopt function returns the option character for the next command line option. When no more option arguments are available, it returns -1 .

What does getopt return in C?

getopt() function in C to parse command line arguments Return Value: The getopt() function returns different values: If the option takes a value, that value is pointer to the external variable optarg. '-1' if there are no more options to process.

What do the colons mean in getopt?

An option character in this string can be followed by a colon (' : ') to indicate that it takes a required argument. If an option character is followed by two colons (' :: '), its argument is optional; this is a GNU extension. getopt has three ways to deal with options that follow non-options argv elements.


2 Answers

Starting with PHP 7.1, getopt supports an optional by-ref param, &$optind, that contains the index where argument parsing stopped. This is useful for mixing flags with positional arguments. E.g.:

user@host:~$ php -r '$i = 0; getopt("a:b:", [], $i); print_r(array_slice($argv, $i));' -- -a 1 -b 2 hello1 hello2 Array (     [0] => hello1     [1] => hello2 ) 
like image 153
adsr Avatar answered Oct 12 '22 11:10

adsr


Nobody said you have ot use getopt. You may do it in any way you like:

$arg_a = null; // -a=YOUR_OPTION_A_VALUE $arg_b = null; // -b=YOUR_OPTION_A_VALUE $arg_c = null; // -c=YOUR_OPTION_A_VALUE  $arg_file = null;  // -file=YOUR_OPTION_FILE_VALUE  foreach ( $argv as $arg ) {     unset( $matches );      if ( preg_match( '/^-a=(.*)$/', $arg, $matches ) )     {         $arg_a = $matches[1];     }     else if ( preg_match( '/^-b=(.*)$/', $arg, $matches ) )     {         $arg_b = $matches[1];     }     else if ( preg_match( '/^-c=(.*)$/', $arg, $matches ) )     {         $arg_c = $matches[1];     }     else if ( preg_match( '/^-file=(.*)$/', $arg, $matches ) )     {         $arg_file = $matches[1];     }     else     {         // all the unrecognized stuff     } }//foreach  if ( $arg_a === null )    { /* missing a - do sth here */ } if ( $arg_b === null )    { /* missing b - do sth here */ } if ( $arg_c === null )    { /* missing c - do sth here */ } if ( $arg_file === null ) { /* missing file - do sth here */ }  echo "a=[$arg_a]\n"; echo "b=[$arg_b]\n"; echo "c=[$arg_c]\n"; echo "file=[$arg_file]\n"; 

I always do it like that and it works. Moreover I can do whatever I want with it.

like image 39
Artur Avatar answered Oct 12 '22 11:10

Artur