使用每个键的输出文件对多列进行排序

时间:2016-07-11 16:43:48

标签: bash

我不确定如何在while循环中使用until循环。

我有一个500,000行的输入文件,如下所示:

#region MyRegion

#endregion

我希望实现的是按照数字顺序对第一列中的数字进行排序,这样我就可以将所有相似的行(例如,以相同数字开头的行)拉入新的文本文件{{1 }}。从那里我想按数字顺序排序第( 9 1 1 0.6132E+02 9 2 1 0.6314E+02 10 3 1 0.5874E+02 10 4 1 0.5266E+02 10 5 1 0.5571E+02 1 6 1 0.5004E+02 1 7 1 0.5450E+02 2 8 1 0.5696E+02 11 9 1 0.6369E+02 ..... )个文件的第四列。排序后,我想将每个已排序的"cluster${i}.txt"文件的第一行写入单个输出文件中。 "cluster${i}.txt"的示例输出是这样的:

"cluster${i}.txt"

以及如下所示的output.txt文件:

"cluster1.txt"

这是我写的:

 1       6       1  0.5004E+02
 1       7       1  0.5450E+02
 1      11       1  0.6777E+02 
 ....

1 个答案:

答案 0 :(得分:3)

如果您的sort -n知道如何处理指数表示法,则只需要一行:

sort -nk 1,4 <in.txt | awk '{ of="cluster" $1 ".txt"; print $0 >>of }'

...或者,也要将每个索引的第一行写为output.txt

sort -nk 1,4 <in.txt | awk '
  {
    if($1 != last) {
      print $0 >"output.txt"
      last=$1
    }
    of="cluster" $1 ".txt";
    print $0 >of
  }'

考虑使用awk实现 - 例如GNU awk - 它将缓存文件描述符,而不是为每个附加重新打开每个输出文件;这将大大提高性能。

顺便说一句,让我们看一下原始剧本的错误:

  • 很慢。真的,真的慢。

    为每一行输入启动awk 20次的新实例(因为while read的整点是迭代各行,所以将awk放在while read内1}}每行运行awk 至少一次)将对性能产生非常明显的影响。并不是说它实际上是这样做的,因为......

  • while read line外循环正在从标准输入读取,而不是temp.txtinput.txt。 因此,如果stdin没有写任何内容,或者如果stdin指向没有像/dev/null这样的内容的源,则该脚本根本不执行循环的内容。 / p>

  • 内循环实际上并没有处理外循环读取的line。正在阅读line,但temp.txt正在进行操作。
  • awk实际上并不在内循环内,而是在外循环中,只是之前内循环。因此,对i的值不同,它不会被运行20次,但每行读取只运行一次,而i的值从之前执行的代码中遗留下来。
  • 空格对于如何解析命令很重要。 [[foo]]错了;它必须是[[ foo ]]

To&#34; fix&#34;内部循环,做我想象你想写的东西,可能看起来像这样:

# this is slow and awful, but at least it'll work.
while IFS= read -r line; do
  i=0
  until [[ $i -ge 20 ]]; do
    awk -v var="$i" '$1 == var' <<<"$line" >>"cluster${i}.txt"
    i=$((i+1))
  done
done <temp.txt

...或者,稍好一些(但仍然不如顶部建议的解决方案):

# this is a somewhat less awful.
for (( i=0; i<=20; i++ )); do
  awk -v var="$i" '$1 == var' <temp.txt >"cluster${i}.txt"
  head -n 1 "cluster${i}.txt"
done >output.txt

请注意,对于整个循环,只需对output.txt重定向一次 - 这意味着我们只打开文件一次。