我有多个具有相同标头和下面不同向量的文件。我需要连接所有它们,但我只想连接第一个文件的标头,并且我不希望连接其他标头,因为它们都是相同的。
例如: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
或兼容的:
将第一个文件的标头写入输出:
head -n 2 file1.txt > all.txt
--
head -n 2
获取文件的前 2 行。添加所有文件的内容:
tail -n +3 -q file*.txt >> all.txt
--
-n +3
打印tail
从第三行到末尾的行; GNUtail
可以采用多个文件名作为参数(作为标准上的通用扩展名),并且 with-q
(也是一种 GNU 扩展名,在 FreeBSD 和 NetBSD 上也受支持)告诉它不要打印带有文件名的标头(readman
),>>
补充道到文件,而不是将其覆盖为>
.
当然你可以将这两个命令放在一行中:
head -n 2 file1.txt > all.txt; tail -n +3 -q file*.txt >> all.txt
或者而不是;
放在&&
它们之间进行成功检查。
请注意,shell glob 扩展默认按词法排序。这意味着虽然file1.txt
tofile9.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
笔记
:
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。