xargs: tar: 由信号 13 终止

Ant*_*lvy 3 pipe tar xargs

我正在运行以下命令以将文件从给定的列表复制git到其他目录,tar以保留权限。

git ls-files -z | xargs -0 tar -c | tar -x -C ~/tmp
Run Code Online (Sandbox Code Playgroud)

这似乎适用于某些存储库,但不适用于我的:

xargs: tar: terminated by signal 13
Run Code Online (Sandbox Code Playgroud)

Ant*_*lvy 5

回答我自己的问题1

信号 13 断管:接收端停止读取,但我们仍在管道中。

我的第一个提示是一个有问题的文件,所以让我们添加-t选项xargs以便它打印命令:

git ls-files -z | xargs -t -0 tar -c | tar -x -C ~/tmp
Run Code Online (Sandbox Code Playgroud)

输出:

tar -c [long list of files (2994 files)]
tar -c [sightly less long list of files (~700 files)]
Run Code Online (Sandbox Code Playgroud)

此时问题就很明显了:我们将两个 tar 调用合并为一个,因此管道损坏了(信号 13)。

事实上,阅读xargs手册,我们可以读到:

命令的命令行会一直建立,直到达到系统定义的限制(除非使用 -n 和 -L 选项)。将根据需要多次调用指定的命令以用完输入项列表。

您可以检查出xargs的限制xargs --show-limits。如果参数长度超过系统限制,xargs 会生成多个命令。

由于命令行的系统限制很高(至少在我的系统上,它是 131072 字节,我的文件相当于 ~3000 个文件),这可以定义为一般情况。这意味着如果文件列表符合系统定义的限制,则初始命令运行良好。

我们可以为每种情况(好吧,至少有 2 个文件)进行重现,通过xargs使用以下-L选项限制每次调用中将抛出的文件数量:

git ls-files -z | xargs -L 1 -t -0 tar -c | tar -x -C ~/tmp
Run Code Online (Sandbox Code Playgroud)

解决方案实际上是xargs完全删除,通过使用 tar 的-T选项,从文件(或-,意思是stdin)中读取文件列表:

git ls-files -z | tar --null -T - -c | tar -x -C ~/tmp
Run Code Online (Sandbox Code Playgroud)

或者

git ls-files | tar -T - -c | tar -x -C ~/tmp
Run Code Online (Sandbox Code Playgroud)

1https : //discuss.circleci.com/t/local-checkout-fails-using-cli-tar-terminates-with-signal-13/28632/14