xargsの不規則な引数の数

xargsの不規則な引数の数

数字はなぜこんなに不規則なのですか?

echo {1..200000} | xargs perl -E 'say "ok:", scalar @ARGV'
ok:23691
ok:21840
ok:21840
ok:21840
ok:20261
ok:18720
ok:18720
ok:18720
ok:18720
ok:15648

標準引数の長さがさらに文明化されました。

perl -E' say "1 " x 900000' | xargs perl -E 'say "ok:", scalar @ARGV'
ok:65520
ok:65520
ok:65520
ok:65520
ok:65520
ok:65520
ok:65520
ok:65520
ok:65520
ok:65520
ok:65520
ok:65520
ok:65520
ok:48240

重要な要素は正確に何ですか?

答え1

重要な数字は(すべての)引数の合計長であり、コマンドバッファサイズxargsが使用することを決定します。

最初は実行するコマンドの固定コマンドラインによって異なり、各呼び出しにxargs引数が与えられます。perl -E 'say "ok:", scalar @ARGV'は32バイトで、文字列を終了するNULバイトを計算します(perl<NUL>-E<NUL>say "ok:", scalar @ARGV<NUL>たとえば、2番目の例では、すべての引数はそれぞれ2バイトです。つまり1<NUL>、.so 32 + 65520 * 2バイトまたは131072 B = 128 * 1024 B = 128kB)。

明らかに、最初の例では引数の長さが異なり、指定された数も異なりますが、論理は同じでなければなりません。たとえば、2番目から4番目の実行までの21840引数は、5ビット引数(引数あたり6バイト)と一致します(21840 * 6 + 32 = 131072)。

コマンドバッファのサイズは実装によって異なりますが、GNU xargsを使用してそれを表示できます。xargs --show-limits私のLinuxでは、次のようになります。

$ echo | xargs --show-limits
Your environment variables take up 2305 bytes
POSIX upper limit on argument length (this system): 2092799
POSIX smallest allowable upper limit on argument length (all systems): 4096
Maximum length of command we could actually use: 2090494
Size of command buffer we are actually using: 131072
Maximum parallelism (--max-procs must be no greater): 2147483647

2番目から最後の行を見ると、まったく同じ数です。

-sたとえば、10kB バッファのみを使用して、使用するバッファサイズを変更できます。

$ perl -E' say "1 " x 90000' | xargs -s 10240 perl -E 'say "ok:", scalar @ARGV' 
ok:5104
ok:5104
ok:5104
...

もちろん、-n個々のパラメータの数も制限する必要があります。

$ echo {1..200000} | xargs -n 10000 perl -E 'say "ok:", scalar @ARGV' 
ok:10000
ok:10000
ok:10000
...

--show-limits環境変数が言及される理由は、コマンドラインパラメータと同じスペースを使用するためであり、バッファサイズをシステム最大値に近づけると、そのサイズも重要になり始めます。

システムで計算するかどうかはわかりません。引数文字列の制限については反対意見がありますが、少なくともxargsはそれを気にしないようです。

答え2

バックグラウンドコンテキストの場合:Linuxおよび他のUnicesには、コマンドに渡すことができる最大引数の数と、場合によっては結果のコマンドラインの合計長さに制限があります。これを処理する必要があります。そうしないとxargs(この場合と同様に)、多数の引数を含むコマンドを実行するとE2BIG失敗することがありますexecvp

ARG_MAX多くのオンラインリソースでは、これがパラメータの標準的な制限であると言いますが、これは間違っています。ARG_MAXこれは単一のパラメータであり、実際にはそれ以前に適用されるより多くの制限がある可能性があります。これらの制限は通常、数量に基づいて適用されます。バイト数量の代わりに結果のコマンドラインに議論(つまり、ポインタ配列に基づいています)この場合、xargsのGNUバージョンは、コマンドが区切られた点がbc_args_exceed_testing_limitユーザー空間で固定長()に基づいて決定されることを知っています。xargs --show-limitsGNU xargsを使用している場合は、次の制限のいくつかを確認できます。

% xargs --show-limits </dev/null |& grep -e arg -e command
POSIX upper limit on argument length (this system): 2090868
POSIX smallest allowable upper limit on argument length (all systems): 4096
Maximum length of command we could actually use: 2086632
Size of command buffer we are actually using: 131072

ソースコードでこれらの制限を表示するには、子を閉じてから以前にパラメータ長のテストを実行することを確認xargs/xargs.cできます。fork()exec()

[...]

      /* If we run out of processes, wait for a child to return and
         try again.  */
      while ((child = fork ()) < 0 && errno == EAGAIN && procs_executing)
        wait_for_proc (false, 1u);

      switch (child)
        {
        case -1:
          die (EXIT_FAILURE, errno, _("cannot fork"));

        case 0:                /* Child.  */
          {
            close (fd[0]);
            child_error = EXIT_SUCCESS;

            prep_child_for_exec ();

            if (bc_args_exceed_testing_limit (argv))
              errno = E2BIG;
            else
              execvp (argv[0], argv);

[...]

この小切手は以下から発行されましたlib/buildcmd.c:

/* Return nonzero if the indicated argument list exceeds a testing limit.
 * NOTE: argv could be declared 'const char *const *argv', but it works as
 * expected only with C++ compilers <http://c-faq.com/ansi/constmismatch.html>.
 */
bool
bc_args_exceed_testing_limit (char **argv)
{
  size_t chars, args;

  for (chars=args=0; *argv; ++argv)
    {
      ++args;
      chars += strlen(*argv);
    }

  return (exceeds ("__GNU_FINDUTILS_EXEC_ARG_COUNT_LIMIT", args) ||
          exceeds ("__GNU_FINDUTILS_EXEC_ARG_LENGTH_LIMIT", chars));
}

次の数字は文字列形式の方が長いため、より多くのスペースを占めるため、xargsは新しいコマンドをより積極的に生成します。

答え3

xargs必要パラメータを調整してサイズを設定するこれはオペレーティングシステムによって制限されます。最初の例の引数が大きくなるため、各呼び出しには適していませんperl。制限内の5文字引数よりも3文字引数を受け入れることができます。

2番目は常に「1」を引数として持つため、65520は常に適切です。

関連情報