【发布时间】:2021-02-06 05:31:12
【问题描述】:
假设我的列表中有大量文件,像这样
$ mkdir inputs
$ for i in $(seq 1 1 10000); do printf "$i\n" > inputs/$i; done
$ find inputs/ -type f -exec readlink -f {} \; > files.txt
我想通过一个看起来像这样的脚本将它们全部传递
$ cat script.py
#!/usr/bin/env python3
import sys
args = sys.argv[1:]
output_file = args[0]
input_files = args[1:]
text = "got {} files".format(len(input_files))
print(text)
with open(output_file, "w") as fout:
fout.write(text + '\n')
我不能一次全部传递它们,因为命令行调用对于系统来说太大而无法处理。但是,xargs 可以为您解决这个问题;
command 的命令行被建立起来,直到它到达一个 系统定义的限制(除非使用 -n 和 -L 选项)。这 指定的命令将根据需要被调用多次以使用 列出输入项列表。一般会少很多 命令的调用比输入中的项目多。这将 通常具有显着的性能优势。有些命令可以 也有用地并行执行;请参阅 -P 选项。
你可以像这样看到这个;
$ cat files.txt | xargs ./script.py output.txt
got 2151 files
got 2152 files
got 2152 files
got 2152 files
got 1393 files
这里,xargs 已将命令分解为 5 个单独的命令并运行每个命令。
但是,输出文件将只有最后一次调用的内容;
$ cat output.txt
got 1393 files
我想要的是获得如下所示的输出文件;
output1.txt # got 2151 files
output2.txt # got 2152 files
output3.txt # got 2152 files
output4.txt # got 2152 files
output5.txt # got 1393 files
有一个问题here 建议在脚本中完成此操作。但是,我的脚本 script.py 不能自己执行此操作,因为它不知道它已经在批处理输入集上运行了 n 次数。在现实生活中,myscript.py 实际上可能是任何我无法修改以完成类似操作的任意第三方程序。
因此,如果我可以对xargs 使用某种参数来自动填充已处理批次的编号n,那就更容易了,例如
$ cat files.txt | xargs ./script.py output.{n}.txt
这样的东西存在吗?有没有什么方法可以用xargs 将输入分块的增加的批次数来填充命令参数?
【问题讨论】:
-
你可以做类似
$ cat files.txt | xargs -IXYZ sh -c "./.script.py output.XYZ.txt"的事情。-IXYZ选项将导致文件名插入到命令中的XYZ字符串中。可能有一种更清洁的方法,但我经常这样做。您还可以对命令使用单引号。注意:这并不完全正确,因为给xargs的列表是一个文件列表,你要做的是给出一个文件名的唯一部分的列表,然后插入它。我想你明白了。 -
是的,我看到了这些建议,但这不起作用。我不能将
xargs输入行用作输出文件的一部分,因为除其他原因之外,output./path/to/input/1.txt不是有效的文件名,而且我不希望每个输入文件都有单独的输出文件。我想使用xargs已经生成的批次并在输出文件名中引用它。 -
你不能通过输出到标准输出并将标准输出重定向到文件来规避这个问题吗?我就是这样做的。另一个类似的替代方法是附加到 output.txt 而不是覆盖它,但输出到 stdout 对我来说似乎更可取。
-
我仍然需要重定向到的文件名。我需要能够基于
n'th 迭代的xargs's 命令调用生成该输出文件的名称 -
@steveb,
xargs -Isigil sh -c '...sigil...'是一个严重的安全风险;它将您的数据直接注入到您的代码中。永远不要那样做;只需省略-Ianything,并编写更像xargs sh -c 'for arg; do ...; arg' _的代码,因此sh的副本将遍历传递给它的项目,如$1、$2等。一行输入'$(rm -rf ~)'$(rm -rf ~)否则会导致非常糟糕的一天。