如何根据第一行将 12000 个文件连接成 4 个文件?

如何根据第一行将 12000 个文件连接成 4 个文件?

我的文件夹中有 12,000 个文件,它们具有类似的命名约定,因为我在较大的文件上使用了 csplit。我需要按文件中的第一行对这些文件进行排序,然后连接相似的文件。

每个文件的第一行都以 "> 1"、"> 2"、"> 3" 或 "> 4" 开头,因此我最终需要所有 "> 4" 文件最终成为一个单一的内聚文件(而且我不需要删除这个 > 4 标头)

例子:

文件 xx1 xx3000 和 xx449 看起来像这样

> 4 speciesX1
ATGC

我需要它最终看起来像

> 4 speciesX1
ATGC
> 4 speciesX3000
ATGC
> 4 speciesX449
ATGC

任何人都可以帮助我,因为我尝试用 sed -n -e '/> 4/,/>/ p' big_file >speciesX.txt 分割原始文件,但它没有打印我想要的块。

答案1

awk 'FNR==1 && ! /^> 4/ {nextfile}1' * > speciesX.txt

如果当前文件的第一行不以 开头,这将跳到下一个文件> 4。所有其他行都打印到标准输出。 stdoutspeciesX.txt由 shell重定向到。

注意:1脚本末尾的评估为 true,导致执行 awk 的默认操作(打印当前行)。这是一个常见的awk习惯用法,因为 awk 脚本本质上是一系列test-condition { action-if-true }规则,其中测试条件或操作都可以省略。如果没有测试条件,则始终执行该操作,如果没有操作,则print默认使用。


修改上面的一行以匹配 、 等并在每次运行时重定向到不同的文件是很容易的/^> 1//^> 2/但是如果您想一次为所有输入文件创建输出文件,只需运行一次脚本,您就可以可以做这样的事情:

awk 'FILENAME ~ /\.out$/ {nextfile};
     FNR==1 && ! /^> [0-9]/ {nextfile};
     FNR==1 {outfile=$2 ".out"};
     {print > outfile}' *.txt

首先,这检查当前输入文件是否以.out.如果是,则跳到下一个文件。如果您的所有输入文件都以例如结尾,则没有必要,.txt但我不知道是否是这种情况(您没有说),最好适当处理这种情况。

然后,它检查每个文件的第一行,如果它与可接受的模式不匹配(即“以 开头>,后跟一个空格,然后是一个数字”),则它会跳到下一个文件。

否则,“.out”将附加到第一行的第二个字段以构造输出文件名。

然后,每行输入都会打印到输出文件名中。您最终会得到文件、、、1.out等。您可以稍后使用 重命名它们。2.out3.out4.outmv

请注意, awk 中的>>>重定向工作方式与 shell 中的工作方式略有不同:

  • Shell 将删除并覆盖现有文件每次>使用时(您必须使用>>附加到文件)。
  • awk 将删除并覆盖文件只有第一次它看到该文件名在脚本的单次运行内,所有后续输出都会附加到同一文件名(在同一脚本运行中)。 >>即使脚本第一次看到文件名,也可以防止擦除和覆盖,即它总是会附加。

顺便说一句,脚本的最后一行{print > outfile}是 awk 规则的示例,其中有一个没有测试条件的操作。这对每个输入行执行(除非先前规则的操作类似于nextnextfile立即跳到下一行或下一个文件)。

答案2

尝试这个:

IFS=$'\n' i=1; for header in $(egrep -m1 '> [0-9]' * -oh | sort | uniq); do grep -rl "$header" . | xargs -I{} cat {} >> file${i}; ((i++)); done

在包含 12000 个文件的目录中运行此命令,之后您将拥有名为 file1、file2、file3 等的单独文件,每个文件包含具有相同标头开头(“> 1”、“> 2”)连接的所有文件一起。

解释:

egrep -m1 '> [0-9]' * -oh | sort | uniq - find all headers starting with "> number" ("> 1", "> 2") and remove duplicates.

IFS=$'\n' i=1; for header in $(...); do ...; done - iterate over the list of headers.

grep -rl "$header" . | xargs -I{} cat {} >> file${i}; ((i++)); - for each header concat all files started by the header to a separate file.

相关内容