使用 awk 过滤 500 个文件,然后将结果 cat 到单个文件

使用 awk 过滤 500 个文件,然后将结果 cat 到单个文件

我所在的目录有几千个文件,但我想要过滤的文件都具有以下语法:*.imputed.*_info

我想使用 awk 过滤掉每个文件中第五列数据的值 > 0.50 的记录,我可以使用以下方法来做到这一点:awk '{if($5 >= .5) {print}}' filename

那也有效。然后,我尝试循环遍历所有 500 个左右的文件,并将每个文件中符合此条件的记录连接起来。

我尝试了以下方法,但语法不正确。

touch snplist.txt
for name in *.imputed.*_info; do
    snps="awk '{if($5 >= .5) {print}}' $name"
    cat snplist.txt "$snps" > snplist.txt
done

答案1

您的代码在每次迭代中都会覆盖输出文件。你实际上也没有打电话awk

你想做的是这样的

awk '$5 >= 0.5' ./*.imputed.*_info >snplist.txt

这将awk立即调用所有文件,并按照 shell 扩展通配模式的顺序逐一遍历它们。如果文件中任何行的第 5 列大于或等于 0.5,则该行将被输出(到snplist.txt)。这是有效的,因为如果没有操作({...}块)与条件关联,则默认操作是输出当前行。

如果您有大的文件数量(数千),这可能会生成“参数列表太长”错误。在这种情况下,您可能需要循环:

for filename in ./*.imputed.*_info; do
    awk '$5 >= 0.5' "$filename"
done >snplist.txt

请注意, 的结果awk不需要存储在变量中。在这里,它只是输出循环(因此循环内的所有命令)被重定向到snplist.txt.

对于数千个文件,这将非常慢,因为awk需要单独调用每个文件。

为了加快速度,如果单次调用有太多文件awk,您可以考虑使用xargs如下所示:

printf '%s\0' ./*.imputed.*_info | xargs -0 awk '$5 >= 0.5' >snplist.txt

这将创建一个文件名列表,并将它们作为一个以 null 结尾的列表printf传递。xargsxargs实用程序将采用这些并awk开始尽可能多的一次,分批。整个管道的输出将被重定向到snplist.txt.

这种xargs替代方案假设您使用的是 Unix,例如 Linux,它有一个xargs命令可以实现非标准-0选项来读取以 nul 结尾的输入。它还假设您使用的是 shell,例如bash,它具有内置 printf实用程序(ksh,OpenBSD 上的默认 shell,在这里不起作用,因为它没有这样的内置实用程序)。


对于zsh外壳(即不是bash):

autoload -U zargs
zargs -- ./*.imputed.*_info -- awk '$5 >= 0.5' >snplist.txt

它使用,它基本上是作为可加载shell 函数zargs的重新实现。有关详细信息,请参阅(加载函数后)和手册。xargszshzargs --helpzshcontrib(1)

答案2

只需这样做:

awk '$5 >= .5' *.imputed.*_info > snplist.txt

答案3

find我有使用这种东西的习惯。

find . -type f -name "*.imputed.*_info" -exec awk '$5 >= 0.5' {} \; > ./snplist.txt

相关内容