对数组进行排序,但可能重复

时间:2014-03-27 21:04:06

标签: arrays bash sorting gawk

我有以下bash脚本,它从文件中提取数字列表。我想维护它们被拉出顺序的日志(这是重要的信息)。所以我得到了一些帮助(可能来自我在这里找到的一个例子)将信息转储到数组中,排序并输出信息。

if [ ! -z "$sort" ]; then
  if [[ $sort == ascending ]]; then
    gawk '/SCF Done/\
           {c++; list[$5]=c}
           END {
                 asorti(list,energies);
                 for (i=1;i<=c;i++)
                 printf("%s%s%d\n",energies[i]," - Optimization Step #",list[energies[i]])
                 print "Total Optimization Steps: "c}
           ' "$1"

唯一的问题是,我发现存储在行$5字段中的值有可能重复。因此,在初始构建数组list[$5]期间,此值可能是非唯一的,因此先前的c值会被覆盖。我想到了一些事情(将$5的值乘以一些随机数,然后再将其重新划分),但如果已经建立(并且更有效)的方法,我不会感到惊讶处理这个我不知道的问题。

以下是grep "SCF Done"

的输出
 SCF Done:  E(UM11L) =  -1267.67892101     A.U. after   41 cycles
 SCF Done:  E(UM11L) =  -1267.64771239     A.U. after   43 cycles
 SCF Done:  E(UM11L) =  -1267.67892101     A.U. after   39 cycles
 SCF Done:  E(UM11L) =  -1267.67892578     A.U. after   24 cycles
 SCF Done:  E(UM11L) =  -1267.67892051     A.U. after   24 cycles
 SCF Done:  E(UM11L) =  -1267.67892201     A.U. after   22 cycles

我切换到gawk格式的全部原因是因为我想拉出那些中间数字,然后还创建一个格式化的输出,如下所示。我最初使用了一个简单的grep "SCF Done"语句,但随后获得格式化,排序等等,开始成为一个相当麻烦的语句。事实仍然是相同的,我希望能够按这些数字排序,同时保留数字和优化步骤之间的相关性(如下所示)。但这些数字并不总是唯一的。

-1267.67892101 - Optimization Step #1
-1267.64771239 - Optimization Step #2
-1267.67892101 - Optimization Step #3
-1267.67892578 - Optimization Step #4
-1267.67892051 - Optimization Step #5
-1267.67892201 - Optimization Step #6

2 个答案:

答案 0 :(得分:2)

为什么要使用gawk而不是sort进行排序?

我从你的代码片段中找不到你要完成的任务,但也许:

grep 'SCF Done' "$1" | cut -f5 | cat -n | sort -k 2

我明白了。如何调用排序而不是使用awk的数组排序。

awk '
    /SCF Done/ {
        printf "%s - Optimization step #%d\n", $5, ++n | "sort"
    } 
    END {
        close("sort")
        print "total steps:", n
    }
' file

看起来像:

-1267.64771239 - Optimization step #2
-1267.67892051 - Optimization step #5
-1267.67892101 - Optimization step #1
-1267.67892101 - Optimization step #3
-1267.67892201 - Optimization step #6
-1267.67892578 - Optimization step #4
total steps: 6

答案 1 :(得分:0)

我错过了排序发挥作用的地方吗?如果您担心重复行,只需跳过该行,如果它与您上一行相同:

$ awk 
    'END { print "total steps: " count }
     /SCF Done/ {
        if ( prev5 == $5 ) {
             continue  # Skip duplicate line
        }
        count++
        printf "%s - Optimization step #%d\n", $5, count
        prev5 = $5
    }'

如果你真的不希望重复一行,请使用数组存储$ 5的值作为数组的键。然后,您可以使用该数组来查看是否曾经击中该行。 awk中的所有数组都是哈希值:

$ awk 
    'END { print "total steps: " count }
     {
        if ( $0 ~ /SCF Done/  ) {
            if ( prev[$5] == 1 ) {
                continue  # Seen that value of $5 before. Skip
            }
            count++
            printf "%s - Optimization step #%d\n", $5, count
            prev[$5] = 1  # Mark that you've printed $5 out
        }
    }'