如何指定 xargs 立即运行包含所有参数的命令?

如何指定 xargs 立即运行包含所有参数的命令?

xargs有一个选项-n用于指定每次运行的命令的最大参数数量。

有没有一种方法可以指定xargs应始终立即运行带有所有提供的参数的任何命令? (就像直接运行带有所有参数的命令而不使用 一样xargs,我并不是试图避免由于系统对命令行长度的限制而导致的失败)

以下不是我的问题。如果它分散了你的注意力,请忽略它。 我不想使用命令替换,因为它会删除NUL和尾随换行符,所以我正在考虑使用xargs作为替代方案。但我不想xargs对多次运行的参数进行分组,因为使用不同参数子集的多次运行的结果可能与使用所有参数的单次运行的结果不同,具体取决于 xargs 执行的命令。所以我想告诉xargs大家始终同时运行所有参数。

答案1

我仍然不确定我明白你在做什么,但是将-x选项(“如果命令行不适合则退出”)与-n设置为巨大值(大于系统限制)的选项结合起来应该:

a) 确保xargs只运行一次,无论有多少个参数

b) 如果由于操作系统或 xargs 内部限制而无法将参数放入单个命令中,则会出现错误。

例子:

$ seq 1 10000 | xargs -n 100000000 -x sh -c 'echo "$#"' sh
10000
$ seq 1 100000 | xargs -n 100000000 -x sh -c 'echo "$#"' sh
xargs: argument list too long

不幸的是,这不适用于BSD 或solaris 的xargs。在 *BSD 上,该-x选项将导致xargs使用单个参数运行其命令,而不是退出:

fz11_2$ jot 10000 1 | xargs -n 10000 -x sh -c 'echo $#' sh | head -3
1
1
1
xargs: sh: terminated with signal 13; aborting

只有一些可笑的小参数-s才会-x触发:

fz11_2$ jot 10000 1 | xargs -s 19 -n 10000 -x sh -c 'echo $#' sh | head -3
xargs: insufficient space for arguments

标准似乎与 GNU xargs 行为匹配:

-n  number
      Invoke utility using as many standard input arguments as
      possible, up to number (a positive decimal integer) arguments
      maximum. Fewer arguments shall be used if:
      + The command line length accumulated exceeds the size specified
        by the -s option (or {LINE_MAX} if there is no -s option).
      + The last iteration has fewer than number, but not zero,
        operands remaining.
-x
      Terminate if a constructed command line will not fit in the
      implied or specified size (see the -s option above).

答案2

你所描述的已经是默认的了。 xargs -n提供要使用的最大参数数,但如果不指定,xargs将使用尽可能多的参数。

您在问题中提到了系统限制,并且您不希望/不需要规避这一点。 xargs将考虑该系统限制,但可能会使用较低的值,如--max-chars-s)选项的用法中所述:

 --max-chars=max-chars
 -s max-chars

最多使用 最大字符数每个命令行的字符数,包括命令和初始参数以及参数字符串末尾的终止空值。最大允许值取决于系统,计算方式为 exec 的参数长度限制减去环境大小,减去 2048 字节的余量。 如果该值大于128KiB,则使用128Kib作为默认值;否则,默认值为最大值。 1KiB 是 1024 字节。

(强调我的)

你可以检查一下它是什么echo | xargs --show-limits。输出示例:

Your environment variables take up 3712 bytes
POSIX upper limit on argument length (this system): 2091392
POSIX smallest allowable upper limit on argument length (all systems): 4096
Maximum length of command we could actually use: 2087680
Size of command buffer we are actually using: 131072
Maximum parallelism (--max-procs must be no greater): 2147483647

这表明我的硬限制是 2087680(略低于 2MiB)。如果你的系统也允许超过128K,你可以通过使用来防止分裂xargs -s 2087680(根据你自己的限制调整)。

旧版本xargs甚至可以让您提供比操作系统允许的更高的限制。在 4.4.2 中,会显示警告,但无论如何都会接受指定的值,并且您会得到与直接运行命令时看到的相同错误:

$ seq 1 2000000 | xargs -s 2100000 echo | wc -l
xargs: value for -s option should be < 2092927
xargs: echo: Argument list too long
0

但在 4.6 版本中,遵守硬限制:

$ seq 1 2000000 | xargs -s 2100000 echo | wc -l
xargs: value for -s option should be <= 2091392
23

答案3

一些澄清:

cmd1 $(cmd2)

以下是 的输出所发生的情况cmd2

  • 在 中bash,NUL 被丢弃。 YMMV 与其他 shell(在zsh它们被保留的情况下,某些 shell 会忽略第一个 NUL 之后的所有内容)。
  • 尾随换行符被删除
  • 结果根据$IFS大多数 shell 中的默认值为 SPC、TAB、NL,在zsh.
  • 每项工作都会受到通配符的影响(除了zsh)。例如*成为当前目录中的非隐藏文件列表。
  • 结果列表作为参数传递给 cmd1.execve()如果该列表(与环境相结合)太大(对于 Linux,如果任何单个参数大于 128KiB),执行此操作的系统调用将会失败。

cmd2 | xargs cmd1

以下是 的输出所发生的情况cmd2

  • 在某些实现中,该输出的字节被解释为字符。例如,在使用 UTF-8 字符集的语言环境中,e2 80 86 字节序列组成了一个 U+2006 字符,它是每人六人的空间字符,通常被视为空白字符。如果某些字节不形成有效字符,根据实现的不同,它们可能会被删除或导致失败,如果输入不是文本,则 POSIX 不会指定该行为
  • 如果有 NUL 字节,那也不是文本,因此行为会因实现而异
  • 如果存在大于 LINE_MAX 的行(在某些系统上可以低至 1024),则行为也是未指定的。
  • xargs根据其自己的预期格式解析其输入。在该格式中,空格和换行符被理解为分隔符(因此尾随换行符将被同样分割),其列表随实现的不同而变化(例如在某些情况下包括 U+2006),并且使用 、 和'...'反斜杠"..."作为引用运算符,以防止对那些分隔符和其他引用运算符进行特殊处理。
  • 结果是一个列表或
  • 在某些实现中,如果这些单词中的任何一个是_,则将其视为文件结束逻辑指示符,并且忽略其后的所有内容。
  • 如果这些字中的任何一个大于某个限制(在许多系统中,低至 255 字节),则行为未指定。
  • 剩余的单词作为参数传递给cmd1,但如果该列表太大,则不会像命令替换情况那样失败,而是xargs尝试容纳尽可能多的单词(带有一些余量,具体取决于实现)以execve()取得成功,并根据需要多次运行该命令以使用所有参数。

现在:

  • 如果您想将 的整个输出cmd2作为一个参数传递给cmd1
    • 如果该输出包含 NUL 字符,则不能,因为这是系统execve()调用的限制,而不是命令替换或xargs.
    • 如果该输出大于 ARG_MAX 限制,则不能(尽管在某些系统上有方法可以增加该限制),同样是exexve().例如,您可以cmd1使用 shell 的内置函数或函数(因为那时不execve()涉及),但即使如此,实际上,zsh在这种情况下也只支持带有 NUL 的参数。
    • 在 Linux 上,如果大于 128KiB,则不能。该限制无法提高。
    • 否则(如果没有 NUL,并且它足够小),您始终可以这样做:out=$(cmd2; echo .); cmd1 "${out%.}"或 使用 GNU xargscmd2 | xargs -0 cmd1

相关内容