a.txt 包含 500,000 列和 2000 行。下面的示例文件仅显示该文件中的前 9 列。该文件的标题位于第一行。
chromosome SNPID rsid position alleleA alleleB 2409086 3514581 3635346
1 1:55487346_C_G rs12117661 55487346 C G 1 0 0
1 1:55487648_A_G rs11588151 55487648 A G 1 0 0
1 1:55489542_C_T rs34232196 55489542 C T 1 0 0
1 1:55490861_T_C rs4500361 55490861 T C 1 0 0
1 1:55491702_T_C rs4927191 55491702 T C 0.894118 0 0
1 1:55491780_A_G rs200159426 55491780 A G 0.894118 0 0
Run Code Online (Sandbox Code Playgroud)
b.txt 包含 45000 列,其中显示每行的列名称。我想根据b.txt从a.txt中提取列。
chromosome
SNPID
rsid
position
alleleA
alleleB
2409086
3635346
Run Code Online (Sandbox Code Playgroud)
c.txt 是我的预期结果。c.txt 应该是一个空格分隔的表,包含 45000 列和 2000 行。
chromosome SNPID rsid position alleleA alleleB 2409086 3635346
1 1:55487346_C_G rs12117661 55487346 C G 1 0
1 1:55487648_A_G rs11588151 55487648 A G 1 0
1 1:55489542_C_T rs34232196 55489542 C T 1 0
1 1:55490861_T_C rs4500361 55490861 T C 1 0
1 1:55491702_T_C rs4927191 55491702 T C 0.894118 0
1 1:55491780_A_G rs200159426 55491780 A G 0.894118 0
Run Code Online (Sandbox Code Playgroud)
我尝试用它cut来解决这个问题,但它显示参数列表太长(因为我需要提取 45000 列)。我知道 awk 可以解决这个问题,但我对 awk 不熟悉,也没有找到任何答案。有没有人有解决方案?
cut -f 1,$(
head -n1 a.txt |
tr ' ' '\n' |
grep -nf b.txt |
sed ':a;$!N;s/:[^\n]*\n/,/;ta;s/:.*//'
) a.txt > c.txt
-bash: /usr/bin/cut: Argument list too long
Run Code Online (Sandbox Code Playgroud)
更新:谢谢你们提供的出色解决方案。
用awk
假设这是filter.awk
NR == FNR { # reading the first file
wanted[$1] = 1
next
}
FNR == 1 {
for (i=1; i<=NF; i++) {
header[i] = $i
}
}
{
for (i=1; i<=NF; i++) {
if (header[i] in wanted) {
printf "%s ", $i
}
}
print ""
}
Run Code Online (Sandbox Code Playgroud)
然后,给定您的示例 a.txt 和
NR == FNR { # reading the first file
wanted[$1] = 1
next
}
FNR == 1 {
for (i=1; i<=NF; i++) {
header[i] = $i
}
}
{
for (i=1; i<=NF; i++) {
if (header[i] in wanted) {
printf "%s ", $i
}
}
print ""
}
Run Code Online (Sandbox Code Playgroud)
我们得到
$ cat b.txt
chromosome
rsid
2409086
Run Code Online (Sandbox Code Playgroud)
这会更快一点:它不必迭代每个记录的所有列
NR == FNR { # reading the first file
wanted[$1] = 1
next
}
FNR == 1 {
n = 0
for (i=1; i<=NF; i++) {
if ($i in wanted) {
cols_to_print[++n] = i
}
}
}
{
for (i=1; i<=n; i++) printf "%s ", $(cols_to_print[i])
print ""
}
Run Code Online (Sandbox Code Playgroud)