【问题标题】:Bash: recursively find maximum value in a column in a fileBash:递归查找文件列中的最大值
【发布时间】:2017-03-06 18:58:25
【问题描述】:

我有一组目录:

RUN1 RUN2 RUN3

在每个目录中,我都有文件。 RUN1 有:

mod1_1 mod1_2 mod1_3

而 RUN2 有:

mod2_1 mod2_2 mod2_3

等等

每个文件都有这样的行(这是 mod1_1):

8.69e-01 2.59e-01 7.82e-01 4.92e-01
8.69e-01 2.56e-01 7.84e-01 4.95e-01
8.72e-01 2.54e-01 7.83e-01 5.00e-01
8.71e-01 2.53e-01 7.84e-01 5.01e-01
8.73e-01 2.53e-01 7.81e-01 4.99e-01

这是 mod1_2:

8.69e-01 2.59e-01 7.82e-01 4.98e-01
8.69e-01 2.56e-01 7.84e-01 4.90e-01
8.72e-01 2.54e-01 7.83e-01 5.00e-01
8.71e-01 2.53e-01 7.84e-01 5.01e-01
8.73e-01 2.53e-01 7.81e-01 4.99e-01

我想为每个 mod 文件创建一个仅包含第 4 列中最小数字的新文件。例如,假设 mod1_1 和 mod2_1 是唯一的文件。我想创建一个新文件,其中包含来自 mod1_1 的第 1 行和来自 mod2_1 的第 2 行:

8.69e-01 2.59e-01 7.82e-01 4.92e-01  
8.69e-01 2.56e-01 7.84e-01 4.90e-01

我想为每个 RUN 目录执行此操作。我试过这个:

#/bin/bash

finddir=$(find -type d -name 'RUN*' | sort) #find the dirs
for i in $finddir; do
        cd $i
        echo $(pwd)
        findfiles=$(find -type f -name 'mod*' | sort -V) #find the files
        echo $findfiles
        for j in $findfiles; do
                s1=$(sort -k3,3 j)
                echo $s1
done

我的问题是排序命令,我不知道如何将结果写入文件。有任何想法吗?

伪代码以防万一:

For each directory RUN*
    For each file mod*
        get the minimum value in column 4, save the line that has that value
    End for 
    Write the lines that had the minimum values to a new file
End for

编辑:仍然有问题。以下是我的修改方式:

#/bin/bash

finddir=$(find -type d -name 'RUN*' | sort) #find the dirs
for i in $finddir; do
        cd $i
        echo $(pwd)
        findfiles=$(find -type f -name 'mod*' | sort -V) #find the files
        for j in $findfiles; do
                s1=$(sort -k 4 -g $j)
                echo -n "$s1"
        done
cd ..
done

我在错误的部分'cd'。这有点好 - 它给了我每行的四个数字 - 但它不只返回每个文件中第 4 列的最小值的行。另外,我仍然不知道如何将最终结果导出到新文件。

【问题讨论】:

    标签: bash


    【解决方案1】:

    对于1_11_2 这些文件中的每一个,以下命令应为您提供该文件中第 4 列中编号最小的行:

    ~]$ cat 1_2
    8.69e-01 2.59e-01 7.82e-01 4.98e-01
    8.69e-01 2.56e-01 7.84e-01 4.90e-01
    8.72e-01 2.54e-01 7.83e-01 5.00e-01
    8.71e-01 2.53e-01 7.84e-01 5.01e-01
    8.73e-01 2.53e-01 7.81e-01 4.99e-01
    

    现在使用sort -k

    ~]$ sort -k 4 test | head -1
    8.69e-01 2.56e-01 7.84e-01 4.90e-01
    

    如果没有head -1,您应该会看到它们是根据第 4 列排序的:

    ]$ sort -k 4 1_2
    8.69e-01 2.56e-01 7.84e-01 4.90e-01
    8.69e-01 2.59e-01 7.82e-01 4.98e-01
    8.73e-01 2.53e-01 7.81e-01 4.99e-01
    8.72e-01 2.54e-01 7.83e-01 5.00e-01
    8.71e-01 2.53e-01 7.84e-01 5.01e-01
    

    编辑

    #!/bin/bash
    resultfile="somefile.txt"
    for d in $(find . -type d -name 'RUN*');
    do
      find $d -type f -name 'mod*' -exec sort -k4 -g {} \; | head -1 >> "$resultfile"
    done
    

    【讨论】:

    • 那么它如何与许多编号的目录一起工作,而不仅仅是 2?
    • 我收到很多这样的错误:./testagain.sh: line 5: : No such file or directory find: sort terminated by signal 13
    • 您没有定义导致这些错误的“$resultfile”。再看一次我的编辑。
    • 大部分都在那里,但仍然得到find: 'sort' terminated by signal 13,并且生成的文件中有一行来自我没想到的文件。
    • 好的,我仍然有这个错误,但解决方案是更改一行:find $d -type f -name 'mod*' -exec sort -k4 -g {} \; | head -1 >> "$resultfile" 如果你写出来,我会接受你的回答!
    【解决方案2】:

    有几个问题: 1.) 在排序命令中使用 $j 而不是 j 2.) 在 echo 上引用您的变量(有关详细信息,请参阅How do I preserve line breaks when storing a command output to a variable in bash?) 3.)你 cd 进入一个目录,但永远不会回去......你可能想回去......

    我测试了您的代码的更简单版本并且(不进入目录)并且有效:

    #!/bin/bash
    
    findfiles=$(find -type f -name 'mod*' | sort -V) #find the files
    for j in $findfiles; do
           echo $j
           s1=$(sort -k 4 -g $j)
           echo "$s1"
     done
    

    请注意,我使用了 sort -g 以便正确处理浮点值,例如如果您将数据更改为(在第二行使用 4.95e-02 而不是 4.95e-01):

    8.69e-01 2.59e-01 7.82e-01 4.92e-01
    8.69e-01 2.56e-01 7.84e-01 4.95e-02
    8.73e-01 2.53e-01 7.81e-01 4.99e-01
    8.72e-01 2.54e-01 7.83e-01 5.00e-01
    8.71e-01 2.53e-01 7.84e-01 5.01e-01
    

    如果没有 -g 则顺序会出错:

     $ cat test.dat | sort -k 4
     8.69e-01 2.59e-01 7.82e-01 4.92e-01
     8.69e-01 2.56e-01 7.84e-01 4.95e-02
     8.73e-01 2.53e-01 7.81e-01 4.99e-01
     8.72e-01 2.54e-01 7.83e-01 5.00e-01
     8.71e-01 2.53e-01 7.84e-01 5.01e-01
    

    使用 -g 代替,订单将正确处理指数:

    $ cat test.dat | sort -k 4 -g
    8.69e-01 2.56e-01 7.84e-01 4.95e-02
    8.69e-01 2.59e-01 7.82e-01 4.92e-01
    8.73e-01 2.53e-01 7.81e-01 4.99e-01
    8.72e-01 2.54e-01 7.83e-01 5.00e-01
    8.71e-01 2.53e-01 7.84e-01 5.01e-01
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-05-03
      • 2021-12-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-18
      • 2013-11-04
      • 1970-01-01
      相关资源
      最近更新 更多