为什么 xargs -I 暗示 -L 1

为什么 xargs -I 暗示 -L 1

我见过为什么'find -exec cmd {} +'需要以'{} +'结尾?这解释了为什么{} +必须位于-exec cmd(*) 的末尾,现在我想知道为什么当您使用(或已弃用的)时 GNUxargs会恢复为每个输入参数一个命令...或者如手册页所述-I-i

-I 替换-str [...] 意味着 -x 和 -L 1。

例如:

$ seq 1 10 | xargs echo
1 2 3 4 5 6 7 8 9 10
$ seq 1 10 | xargs -I {} echo {}
1
2
3
4
5
6
7
8
9
10

xargs 手册页的 BUGS 部分仅说明:

-L 选项与 -I 选项不兼容,但也许不应该兼容。

当您使用 -I 选项时,从输入读取的每一行都会在内部缓冲。这意味着与 -I 选项一起使用时 xargs 将接受的输入行长度有上限。要解决此限制,您可以使用 -s 选项来增加 xargs 使用的缓冲区空间量,还可以使用 xargs 的额外调用来确保不会出现很长的行。

两者都不能解释原因。

使用的主要原因之一xargs是减少执行的命令数量(运行一个cp或使用 1000 个源文件名比运行 1000个或每个使用 1 个源文件名mv更好),并且这种限制在许多情况下阻止了......大多数因为大多数 UNIX 命令都希望源(例如文件列表)位于目标(例如目录)之前。cpmv

那么,为什么xargs会有这样的限制呢?


更新2015-11-05

我最近创建了一个 freebsd 10.0 VM,发现 freebsd 的版本xargs有一个-J选项可以处理这个问题。

-J replstr

如果指定此选项,xargs 将使用从标准输入读取的数据来替换第一次出现的 replstr,而不是将该数据附加到所有其他参数之后。此选项不会影响从输入读取的参数数量 (-n),或 xargs 将生成的命令的大小 (-s)。该选项只是移动那些参数将被放置在执行的命令中的位置。 replstr 必须显示为 xargs 的不同参数。例如,如果它位于带引号的字符串中间,则不会被识别。此外,只有第一次出现的 replstr 才会被替换。例如,以下命令会将当前目录中以大写字母开头的文件和目录列表复制到 destdir:

/bin/ls -1d [A-Z]* | xargs -J % cp -Rp % destdir

(*) 本质上,“因为 POSIX 规范是这么说的”。在我看来,他们应该更加努力地寻找一种解决方案,允许{}出现在 中的任何位置-exec ... +,或者至少需要像 cp 和 mv 这样的标准工具来拥有像 GNU 的-t选项一样的选项来反转源和目标。

答案1

(因为这没有回答问题,所以这应该是一条评论,但太长了 - 所以将其视为一条评论)。

作为 FreeBSD xargs 的替代方案,您可以使用 GNU Parallel,它没有此限制。它甚至支持重复上下文:

seq 10 | parallel -Xj1 echo con{}text 
seq 10 | parallel -mj1 echo con{}text 

GNU Parallel 是一个通用并行器,可以轻松地在同一台计算机或多台您可以通过 ssh 访问的计算机上并行运行作业。它通常可以代替for循环。

如果您想要在 4 个 CPU 上运行 32 个不同的作业,则并行化的直接方法是在每个 CPU 上运行 8 个作业:

简单的调度

相反,GNU Parallel 在完成后会生成一个新进程 - 保持 CPU 处于活动状态,从而节省时间:

GNU 并行调度

安装

如果您的发行版未打包 GNU Parallel,您可以进行个人安装,不需要 root 访问权限。这样做可以在 10 秒内完成:

(wget -O - pi.dk/3 || curl pi.dk/3/ || fetch -o - http://pi.dk/3) | bash

对于其他安装选项,请参阅http://git.savannah.gnu.org/cgit/parallel.git/tree/README

了解更多

查看更多示例:http://www.gnu.org/software/parallel/man.html

观看介绍视频:https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1

浏览本教程:http://www.gnu.org/software/parallel/parallel_tutorial.html

注册电子邮件列表以获得支持:https://lists.gnu.org/mailman/listinfo/parallel

答案2

POSIX 不定义事物,POSIX 只是描述现有的实现以成为标准。

find -exec + 是 David Korn 于 1989 年为 SVr4 引入的,考虑到它是很晚才添加到标准中的,所以几乎没有机会对其进行更改。

但目前的标准没有问题,你可以随时调用:

find . -type f -exec sh -c 'somecommand "$@" somedir' sh {} +

所以你会看到没有限制,也没有必要使用非标准选项。

关于 xargs:您正在询问供应商特定实现的内部结构。显然,除非供应商特定实现的作者正在此处阅读和编写,否则您不太可能在这里获得问题的有用答案。

然而,我的示例对于 xargs 也以类似的方式工作。

相关内容