gpt4 book ai didi

shell - 将文件名添加到 xargs 和 awk 命令的输出中

转载 作者:行者123 更新时间:2023-12-05 00:49:10 27 4
gpt4 key购买 nike

我有一个充满 .txt 文件的目录,每个文件都有两列和多行(> 10000)。对于这些文件中的每一个,我试图在第二列中找到最大值,并将第 1 列和第 2 列中的相应条目打印到输出文件。为此,我有一个有效的 awk 命令。

find ./ -name "*.txt" | xargs -I FILE awk '{if(max<$2){max=$2;datum=$1}}END{print datum, max}' FILE >> out.txt

但是,我还想用每对数字打印相应输入文件的名称。输出将类似于:

file1.txt datum1 max1
file2.txt datum2 max2



为此,我试图从这个类似的问题中汲取灵感:
add filename to beginning of file using find and sed ,
但我无法得到一个有效的解决方案。到目前为止,我最大的努力看起来像这样
find ./ -name "*.txt" | xargs -I FILE echo FILE | awk '{if(max<$2){max=$2;datum=$1}}END{print datum, max}' FILE >> out.txt

但我收到错误:

awk: can't open file FILE
source line number 1



我尝试了各种其他方法,这些方法可能离正确还有几个字符:
(1)
find ./ -name "*.txt" | xargs -I FILE -c "echo FILE ; awk '{if(max<$2){max=$2;datum=$1}}END{print datum, max}' FILE" >> out.txt  

(2)
find ./ -name "*.txt" -exec sh -c "echo {} && awk '{if(max<$2){max=$2;datum=$1}}END{print datum, max}' {}" \; >> out.txt

我不介意使用什么命令(xargs 或 exec 或其他什么),我只关心输出。

最佳答案

如果所有 .txt 文件都在当前目录中,请尝试 (GNU awk):

awk '{if(max=="" || max<$2+0){max=$2;datum=$1}}ENDFILE{print FILENAME, datum, max; max=""}' *.txt

如果要在当前目录及其所有子目录中搜索 .txt 文件,请尝试:
find . -name '*.txt' -exec awk '{if(max=="" || max<$2+0){max=$2;datum=$1}}ENDFILE{print FILENAME, datum, max; max=""}' {} +

因为现代 find有一个 -exec Action ,命令 xargs很少需要了。

这个怎么运作
  • {if(max=="" || max<$2+0){max=$2;datum=$1}}
    这将找到最大的第 2 列并将其和相应的值保存在第 1 列中。
  • ENDFILE{print FILENAME, datum, max; max=""}
    到达每个文件的末尾后,这将打印文件名和第 1 列和第 2 列,从第 2 列最大的那一行开始。

    此外,在每个文件的末尾,max被重置为空字符串。

  • 例子

    考虑一个包含这三个文件的目录:
    $ cat file1.txt
    1 1
    2 2
    $ cat file2.txt
    3 12
    5 14
    4 13
    $ cat file3.txt
    1 0
    2 1

    我们的命令产生:
    $ awk '{if(max=="" || max<$2+0){max=$2;datum=$1}}ENDFILE{print FILENAME, datum, max; max=""}' *.txt
    file1.txt 2 2
    file2.txt 5 14
    file3.txt 2 1

    BSD awk

    如果我们不能使用 ENDFILE,请尝试:
    $ awk 'FNR==1 && NR>1{print f, datum, max; max=""} max=="" || max<$2+0{max=$2;datum=$1;f=FILENAME} END{print f, datum, max}' *.txt
    file1.txt 2 2
    file2.txt 5 14
    file3.txt 2 1

    因为一个 awk 进程可以分析许多文件,所以这种方法应该很快。
  • FNR==1 && NR>1{print f, datum, max; max=""}
    每次我们开始一个新文件时,我们都会打印前一个文件的最大值。

    在 awk 中,FNR是当前文件的行号,NR是到目前为止读取的总行数。当FNR==1 && NR>1 ,这意味着我们至少完成了一个文件,然后开始处理下一个文件。
  • max=="" || max<$2+0{max=$2;datum=$1;f=FILENAME}
    像以前一样,我们捕获第 2 列的最大值和第 1 列的相应数据。我们还将文件名记录为变量 f .
  • END{print f, datum, max}
    读完最后一个文件后,我们打印它的最大行。
  • 关于shell - 将文件名添加到 xargs 和 awk 命令的输出中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48144452/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com