如何连接文件前四行的每四行

How to concatenate every four lines for the first four lines of a file

我不确定问这个问题的最佳措辞,但我正在尝试将前四行连接到接下来的四行,依此类推,直到文件结束。

我的数据如下:

aggaacgtgagttgaaaattgaagcgacaaacttggtttcatgtcctgtttgtggaaaga
catctattgttagagacaatatattgtctgatctgacttatctgcatgttc---------
 .     **    ..* * *. * .* * .*..**..**  .  * ****.         

gcataaaaggaatggacacaatcataaatgaacatcttgatatctgccttacaagaaggt
----------tgtggattcctttctttttccttttggagatatctgccttacaagaaggt
           .****. *  *. *   *   . *   **********************

ccaaacgaaaacttacccaacgcacactacttcagtttggtgttggatcaagtaccaaaa
ccaaacgaaaacttacccaacgcacactacttcagtttggtgttggatcaagtaccaaaa
************************************************************

我正在尝试 merge/concatenate 每四行到之前的四行来创建一个水平文件格式,如下所示:

aggaacgtgagttgaaaattgaagcgacaaacttggtttcatgtcctgtttgtggaaagagcataaaaggaatggacacaatcataaatgaacatcttgatatctgccttacaagaaggtccaaacgaaaacttacccaacgcacactacttcagtttggtgttggatcaagtaccaaaa
catctattgttagagacaatatattgtctgatctgacttatctgcatgttc-------------------tgtggattcctttctttttccttttggagatatctgccttacaagaaggtccaaacgaaaacttacccaacgcacactacttcagtttggtgttggatcaagtaccaaaa
 .     **    ..* * *. * .* * .*..**..**  .  * ****.                    .****. *  *. *   *   . *   **********************************************************************************

我知道我可以使用 paste - - 每隔一行删除一个换行符,但是将文件的前四行每隔四行粘贴到一起的最简单方法是什么?

你可以使用 :

#!/bin/perl

use strict;
use warnings;

my %lines;                   # hash container to store the lines

while(<>) {                  # read lines from stdin
    chomp;                   # remove newline
    my $idx = ($. - 1) % 4;  # calculate index of line [0,4)
    $lines{$idx} .= $_;      # concatename the current line to what's at $idx
}

# Done, print the result:
for(my $i = 0; $i < 4; ++$i) {
    print $lines{$i} ."\n";
}

好像是每三行中间用一个空行隔开。如果是这种情况,这个 awk 程序可能就是您要找的:

awk 'BEGIN { RS = ""; FS = "\n" }
           { for (i = 1; i <= 3; ++i) line[i] = line[i] $i }
     END   { for (i = 1; i <= 3; ++i) print line[i] }
' file

一种方法是将每一行存储在一个数组中以在末尾打印:

awk -v n=4 '
{ a[NR]=[=10=] }
END {
  for (i=1; i<=n; i++) {
    for (j=i; j<=NR; j+=n) {
      printf "%s", a[j]
    }
    print ""
  }
}' file

另一种方法是读取文件4次(这样可以避免将整个文件存储在内存中):

awk -v n=4 '
  FNR==1 {
    if (c++) print ""
  }
  ! ((NR-c)%n) { printf "%s", [=11=] }
  END {
    if (c) print ""
  }
' file file file file

这可以使用 shell 循环来完成:

for c in 1 2 3 4
do
  awk '! ((NR-c)%n)' n=4 c="$c" ORS= file
  echo
done

上述任何一个的输出将是:

aggaacgtgagttgaaaattgaagcgacaaacttggtttcatgtcctgtttgtggaaagagcataaaaggaatggacacaatcataaatgaacatcttgatatctgccttacaagaaggtccaaacgaaaacttacccaacgcacactacttcagtttggtgttggatcaagtaccaaaa
catctattgttagagacaatatattgtctgatctgacttatctgcatgttc-------------------tgtggattcctttctttttccttttggagatatctgccttacaagaaggtccaaacgaaaacttacccaacgcacactacttcagtttggtgttggatcaagtaccaaaa
 .     **    ..* * *. * .* * .*..**..**  .  * ****.                    .****. *  *. *   *   . *   **********************************************************************************

如果您的文件很大,将其全部内容存储在变量中或对其进行多次处理可能会导致内存或性能问题。动态生成 4 个不同的文件并将它们连接在一起可能会有所帮助。在 bash 脚本中使用 GNU awk 的示例:

#!/usr/bin/env bash

# file myScript.sh

unset tmpdir
trap 'rm -rf -- "$tmpdir"' EXIT TERM

declare input="${1:--}"
declare tmpdir

tmpdir=$(mktemp -d) || exit 1
awk -v t="$tmpdir" '
{
  printf("%s", [=10=]) > t "/file." (NR-1)%4 ".part"
}
END {
  for(i=0; i<4; i++) print "" > t "/file." i ".part"
}' "$input"
cat "$tmpdir"/file.{0..3}.part

脚本使用一个临时目录来存储4个中间文件。陷阱会在正常终止时或脚本在其正常结束之前终止时删除临时目录。用法:./myScript.sh [FILE]。没有 FILE,或者当 FILE- 时,脚本读取标准输入。

awk 脚本将进行更改

awk '
{
    line = (line == "" ? [=10=] : line[=10=]);
    if (++i == 4) {
        print line;
        i = 0; line="";
    }
}
END {
    if (line != "")
        print line;
}'

您可以将文件名添加到 awk 命令以处理多个文件或从标准输入读取命令显示。您可以在 line[=15=] 之间添加一个分隔符字符,如果您希望这些行由某个字符串分隔,或者将 4 更改为您想要的行数。例如,将行分成三组,并用 @ 个字符分隔:

awk '
{
    line = (line == "" ? [=11=] : line"@"[=11=]);
    if (++i == 3) {
        print line;
        i = 0; line="";
    }
}
END {
    if (line != "")
        print line;
}'