笔记

笔记

我有多个具有相同标头和下面不同向量的文件。我需要连接所有它们,但我只想连接第一个文件的标头,并且我不希望连接其他标头,因为它们都是相同的。

例如:file1.txt

<header>INFO=<ID=DP,Number=1,Type=Integer>
<header>INFO=<ID=DP4,Number=4,Type=Integer>
A
B 
C

文件2.txt

<header>INFO=<ID=DP,Number=1,Type=Integer>
<header>INFO=<ID=DP4,Number=4,Type=Integer>
D
E 
F

我需要输出是

<header>INFO=<ID=DP,Number=1,Type=Integer>
<header>INFO=<ID=DP4,Number=4,Type=Integer>
A
B
C
D
E 
F

我可以用 R 编写脚本,但我需要在 shell 中使用它?

答案1

另一种解决方案,类似于cat+grep上面的“”,使用head与GNUtail或兼容的:

  1. 将第一个文件的标头写入输出:

    head -n 2 file1.txt > all.txt
    

    --head -n 2获取文件的前 2 行。

  2. 添加所有文件的内容:

    tail -n +3 -q file*.txt >> all.txt
    

    ---n +3打印tail从第三行到末尾的行; GNUtail可以采用多个文件名作为参数(作为标准上的通用扩展名),并且 with -q(也是一种 GNU 扩展名,在 FreeBSD 和 NetBSD 上也受支持)告诉它不要打印带有文件名的标头(read man), >>补充道到文件,而不是将其覆盖为>.

当然你可以将这两个命令放在一行中:

head -n 2 file1.txt > all.txt; tail -n +3 -q file*.txt >> all.txt

或者而不是;放在&&它们之间进行成功检查。

请注意,shell glob 扩展默认按词法排序。这意味着虽然file1.txttofile9.txt将按数字排序,但file10.txt将在file1.txt和之间排序file2.txt(或者甚至可能在之前,具体file1.txt取决于区域设置)。如果使用zsh,则用于file*.txt(n)数字排序。

答案2

如果您知道如何在 R 中执行此操作,那么请务必在 R 中执行此操作。对于经典的 unix 工具,这在 awk 中最自然地完成。

awk '
    FNR==1 && NR!=1 { while (/^<header>/) getline; }
    1 {print}
' file*.txt >all.txt

awk 脚本的第一行与文件的第一行 ( FNR==1) 匹配,除非它也是所有文件的第一行 ( NR==1)。当满足这些条件时,执行表达式while (/^<header>/) getline;,这会导致 awk 继续读取另一行(跳过当前行),只要当前行与 regexp 匹配^<header>。 awk 脚本的第二行打印除之前跳过的行之外的所有内容。

答案3

尝试这样做:

$ cat file1.txt; grep -v "^<header" file2.txt
<header>INFO=<ID=DP,Number=1,Type=Integer>
<header>INFO=<ID=DP4,Number=4,Type=Integer>
A
B 
C
D
E 
F

笔记

  • -v标志意味着反转匹配
  • ^正则表达式, 方法字符串的开头
  • 如果你有一堆文件,你可以这样做

:

array=( files*.txt )
{ cat ${array[@]:0:1}; grep -v "^<header" ${array[@]:1}; } > new_file.txt

它是数组切片技术。

答案4

array=( *.txt );head -1 ${array[0]} > all.txt; tail -n +2 -q ${array[@]:0} >> all.txt

假设您使用的文件夹中的 .txt 文件具有相同的标头,需要组合/连接,此代码会将 txt 文件全部组合到全部.txt只有一个标头。第一行(用分号分隔的行)收集要连接的所有文本文件,第二行将第一个 txt 文件中的标题输出到全部.txt,最后一行连接所有收集的没有标题的文本文件(通过从第 2 行开始连接)并将其附加到全部.txt

相关内容