【问题标题】:After using PHP's getopt(), how can I tell what arguments remain?使用 PHP 的 getopt() 后,我如何知道还有哪些参数?
【发布时间】:2013-10-03 12:25:30
【问题描述】:

好的,所以 PHP 有一个内置的getopt() 函数,它返回有关用户提供的程序选项的信息。只是,除非我错过了什么,否则它完全是无聊的!来自手册:

选项的解析将在找到的第一个非选项处结束,随后的任何内容都将被丢弃。

所以getopt() 只返回一个带有 valid 和 parsed 选项的数组。通过查看$argv,您仍然可以看到整个原始命令行,它保持未修改,但是您如何告诉在该命令行getopt() 中的哪里 停止解析参数?如果您想将命令行的其余部分视为其他内容(例如文件名),则必须了解这一点。

这是一个例子......

假设我想设置一个脚本来接受以下参数:

Usage: test [OPTION]... [FILE]...

Options:
  -a  something
  -b  something
  -c  something

那我可能会这样打电话给getopt()

$args = getopt( 'abc' );

如果我这样运行脚本:

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

我应该期望有以下数组返回给我:

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

所以问题是这样的:我到底怎么知道这三个未解析的非选项FILE 参数从$argv[ 3 ] 开始???

【问题讨论】:

  • 您可以查看 Console_GetOpt (stackoverflow.com/questions/1023095/…),但它需要 PEAR。
  • 您将文件指定为最后一个参数,因此您可以执行$argv[count($argv) - 1]
  • @EaterOfCode:这还不够。您可以指定任意数量的文件,因此您需要知道最后有多少未解析的非选项参数。
  • 如果您没有需要值或可选值的参数,您可以简单地修剪所有以连字符开头的$argv 元素,只留下非选项参数:preg_grep('/^-/', $argv, PREG_GREP_INVERT)
  • 哈哈,在解决了这个问题 30 分钟后,我找到了自己的旧评论。 ;) 解决方案仍然有价值。更新用法:$argv = array_values(preg_grep('/^-/', $argv, PREG_GREP_INVERT));

标签: php getopt


【解决方案1】:

从 PHP 7.1 开始,getopt 支持可选的 by-ref 参数 &$optind,其中包含参数解析停止的索引。这对于将标志与位置参数混合很有用。例如:

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
)

【讨论】:

  • 我在 2021 年写道,我仍然受限于 PHP 5.5,我无法使用 getopt() 的第三个选项。
【解决方案2】:

没有人说你没有使用getopt。你可以用任何你喜欢的方式来做:

$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";

我总是这样做,而且效果很好。而且我可以用它做任何我想做的事情。

【讨论】:

  • 是的,但我更希望能够使用内置库,而不是随处携带我自己的库。对我来说,这似乎是内置库中的一个严重缺陷。(此外,您的示例代码将无法处理,例如,我的示例中的 -bccc 命令行参数。我相信还有更完整的示例那里有 PHP 的命令行解析器,但这有点违背了这个问题的重点!)
  • 直接使用strtok,foreach效果会更好。
  • 我遇到过几种情况,PHP 的内置函数有点偏离目标,我需要自己构建。我认为这不应该被否决,因为它创造性地试图解决 PHP 的内置函数无法回答的问题。这不是一个完美的答案,但也不是一个糟糕的答案。
  • @ImmortalFirefly:虽然它没有解决问题——我已经知道我可以自己动手了!我的问题是关于如何将 PHP 的内置 getopt() 用于预期目的。
【解决方案3】:

以下可用于获取命令行选项后面的任何参数。 它可以在调用 PHP 的 getopt() 之前或之后使用,结果不变:

# $options = getopt('cdeh');

$argx = 0;

while (++$argx < $argc && preg_match('/^-/', $argv[$argx])); # (no loop body)

$arguments = array_slice($argv, $argx);

$arguments 现在包含任何前导选项之后的任何参数。 或者,如果您不希望将参数放在单独的数组中,则 $argx 是第一个实际参数的索引:$argv[$argx]

如果没有参数,在任何前导选项之后,那么:

  • $arguments 是一个空数组 [],并且
  • count($arguments) == 0,和
  • $argx == $argc

【讨论】:

  • 这是一个糟糕的答案!它会跳过任何以- 开头的命令行参数,并假定其余的都是非选项参数!如果我运行这样的命令行:./example --name Bob -s 23 会怎样?在这里,我可能有 no 非选项参数(如果 --name 和 -s 都采用选项参数),您的代码会说 ["Bob", "-s", "23"] 是非选项参数。问题是直到你解析选项,你不能告诉哪些参数是非选项参数。 PHP 的getopt() 需要以某种方式指出哪些参数不是选项的一部分。它没有。
【解决方案4】:

看看 GetOptionKit 以摆脱标志解析。

http://github.com/c9s/GetOptionKit

GetOptionKit 可以轻松集成到您的命令行脚本中。支持类型约束、值验证等。

【讨论】:

  • 谢谢。我知道还有其他图书馆可以做到这一点。我只是想知道是否有办法使用 PHP 的原生 getopt() 函数来做到这一点。不过好像没有。
猜你喜欢
  • 2021-01-18
  • 1970-01-01
  • 2022-12-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-12
相关资源
最近更新 更多