Linux 如何通过匹配标题拆分列?

Linux 如何通过匹配标题拆分列?,linux,awk,Linux,Awk,我在想是否有办法通过匹配标题来拆分列 数据如下所示 ID_1 ID_2 ID_3 ID_6 ID_15 value1 0 2 4 7 6 value2 0 4 4 3 8 value3 2 2 3 7 8 我只想获取ID_3和ID_15上的列 ID_3 ID_15 4 6 4 8 3 8 如果我

我在想是否有办法通过匹配标题来拆分列

数据如下所示

         ID_1   ID_2   ID_3   ID_6   ID_15
value1   0      2      4      7      6
value2   0      4      4      3      8
value3   2      2      3      7      8
我只想获取ID_3和ID_15上的列

ID_3   ID_15
4      6
4      8
3      8
如果我知道列的顺序,awk可以简单地将它分隔开 然而,我有一张很大的桌子,手里只有一张ID列表。
我仍然可以使用awk吗?或者在linux中有更简单的方法吗

$cat c.awk
$ cat c.awk
NR == 1 {
    for (i=1; i<=NF; ++i) {
        if ($i == "ID_3") col_3 = (i + 1)
        if ($i == "ID_15") col_15 = (i + 1)
    }
    print "ID_3", "ID_15"
}

NR > 1 { print $col_3, $col_15 }


$ awk -f c.awk c.txt
ID_3 ID_15
4 6
4 8
3 8
NR==1{ 对于(i=1;i1{print$col_3,$col_15} $awk-f c.awk c.txt ID_3 ID_15 4 6 4 8 3 8
$cat c.awk
NR==1{
对于(i=1;i1{print$col_3,$col_15}
$awk-f c.awk c.txt
ID_3 ID_15
4 6
4 8
3 8

您可以选择以下方式:

BEGIN { 
    keys["ID_3"]
    keys["ID_15"] 
}

NR == 1 { 
    for (i = 1; i <= NF; ++i) 
        if ($i in keys) cols[++n] = i 
}

{ 
    for (i = 1; i <= n; ++i) 
        printf "%s%s", $(cols[i]+(NR>1)), (i < n ? OFS : ORS) 
}
在处理文件之前,将在
keys
数组中设置键,对应于感兴趣的列标题

在第一行,记录包含
cols
数组中一个键的所有列号


循环遍历每个COL并将其打印出来,然后是输出字段分隔符OFS或输出记录分隔符ORS,具体取决于它是否是最后一个。
$(cols[i]+(NR>1))
处理第一行之后的行在开始处有一个额外字段的事实,因为
NR>1
对于这些行将为true(1),对于第一行将为false(0)。

您可以这样做:

BEGIN { 
    keys["ID_3"]
    keys["ID_15"] 
}

NR == 1 { 
    for (i = 1; i <= NF; ++i) 
        if ($i in keys) cols[++n] = i 
}

{ 
    for (i = 1; i <= n; ++i) 
        printf "%s%s", $(cols[i]+(NR>1)), (i < n ? OFS : ORS) 
}
在处理文件之前,将在
keys
数组中设置键,对应于感兴趣的列标题

在第一行,记录包含
cols
数组中一个键的所有列号

循环遍历每个COL并将其打印出来,然后是输出字段分隔符OFS或输出记录分隔符ORS,具体取决于它是否是最后一个。
$(cols[i]+(NR>1))
处理第一行之后的行在开始处有一个额外字段的事实,因为
NR>1
对于这些行为true(1),对于第一行为false(0)。

请尝试下面的脚本:

 #!/bin/sh

file="$1"; shift

awk -v cols="$*" '
BEGIN{
split(cols,C)
OFS=FS="\t"
getline
split($0,H)
for(c in C){
    for(h in H){
        if(C[c]==H[h])F[i++]=h
    }
}
}
{ l="";for(f in F){l=l $F[f] OFS}print l }

' "$file"
在命令行类型中:

[sumit.gupta@rpm01 ~]$ test.sh filename ID_3 ID_5
请尝试以下脚本:

 #!/bin/sh

file="$1"; shift

awk -v cols="$*" '
BEGIN{
split(cols,C)
OFS=FS="\t"
getline
split($0,H)
for(c in C){
    for(h in H){
        if(C[c]==H[h])F[i++]=h
    }
}
}
{ l="";for(f in F){l=l $F[f] OFS}print l }

' "$file"
在命令行类型中:

[sumit.gupta@rpm01 ~]$ test.sh filename ID_3 ID_5

输入格式没有很好的定义,但有几种简单的方法,
awk
perl
sqlite

(FNR==1) {
    nocol=split(col,ocols,/,/)    # cols contains named columns
    ncols=split("vals " $0,cols)  # header line
    for (nn=1; nn<=ncols; nn++) colmap[cols[nn]]=nn  # map names

    OFS="\t"                      # to align output
    for (nn=1; nn<=nocol; nn++) printf("%s%s",ocols[nn],OFS)
    printf("\n")                  # output header line 
}
(FNR>1) { # read data
    for (nn=1; nn<=nocol; nn++)  {
        if (nn>1) printf(OFS)     # pad
        if (ocols[nn] in colmap) { printf("%s",$(colmap[ocols[nn]])) }
        else                     { printf "--" } # named column not in data
    }  
    printf("\n") # wrap line
}

$ nawk -f mycols.awk -v col=ID_3,ID_15 data
ID_3    ID_15   
4       6
4       8
3       8
这会在第一行中添加一个虚拟的第一列“VAL”,然后以逗号分隔的方式打印每一行,这是通过对
$1
进行看似无意义的赋值来实现的,但这会导致重新计算
$0
,将FS(空格/制表符)替换为
OFS
(逗号)

使用
.once
.output
将输出发送到文件()。根据需要使用
.headers on
.headers off
。 sqlite非常乐意创建一个未命名的列,因此您不必在标题行的第一列中添加名称,但需要确保所有输入行和格式的列数相同


如果在
.import
过程中出现“预期的X列但发现的Y列”错误,则需要对此数据格式进行一些清理。

输入格式没有很好的定义,但有几种简单的方法,
awk
perl
sqlite

(FNR==1) {
    nocol=split(col,ocols,/,/)    # cols contains named columns
    ncols=split("vals " $0,cols)  # header line
    for (nn=1; nn<=ncols; nn++) colmap[cols[nn]]=nn  # map names

    OFS="\t"                      # to align output
    for (nn=1; nn<=nocol; nn++) printf("%s%s",ocols[nn],OFS)
    printf("\n")                  # output header line 
}
(FNR>1) { # read data
    for (nn=1; nn<=nocol; nn++)  {
        if (nn>1) printf(OFS)     # pad
        if (ocols[nn] in colmap) { printf("%s",$(colmap[ocols[nn]])) }
        else                     { printf "--" } # named column not in data
    }  
    printf("\n") # wrap line
}

$ nawk -f mycols.awk -v col=ID_3,ID_15 data
ID_3    ID_15   
4       6
4       8
3       8
这会在第一行中添加一个虚拟的第一列“VAL”,然后以逗号分隔的方式打印每一行,这是通过对
$1
进行看似无意义的赋值来实现的,但这会导致重新计算
$0
,将FS(空格/制表符)替换为
OFS
(逗号)

使用
.once
.output
将输出发送到文件()。根据需要使用
.headers on
.headers off
。 sqlite非常乐意创建一个未命名的列,因此您不必在标题行的第一列中添加名称,但需要确保所有输入行和格式的列数相同


如果在
导入过程中出现“预期X列,但发现Y列”错误,则需要对此数据格式进行一些清理。

请参阅,例如,请参阅,您不能将
用于(f中的f)
若要按顺序迭代,即使索引是整数,也会根据awk实现定期以错误的顺序输出列。此外,千万不要命名变量
l
,因为它看起来太像
1
,而这不是使用
getline
-请参见..不能使用
for(f中的f)
即使索引是整数,也要按顺序迭代,这会根据awk实现定期以错误的顺序输出列。此外,千万不要命名变量
l
,因为它看起来太像
1
,而这不是使用
getline
的方式-请看..是的,它有点密集。我已经编辑过添加它n脚本形式。是的,我很懒…我编辑它是为了使用正确的一个谢谢。它看起来简单明了。但是,我正在尝试获得数百个匹配的标题。在脚本中编写标题匹配规则似乎不可行。但是,我有一种感觉。谢谢。是的,它有点密集,不可否认。我编辑是为了在脚本形式中添加它。是的我很懒…我编辑它是为了使用正确的标题谢谢。它看起来简单明了。但是,我正在尝试获取数百个匹配的标题。在脚本中编写标题匹配规则似乎不可行。但是,我有一种感觉。谢谢。谢谢。如果我需要获取数百个匹配的标题呢?至少我从你那里得到了一些想法你的建议。谢谢。谢谢。如果我需要得到数百个匹配的标题呢?至少我从你的建议中得到了一些想法。谢谢。非常感谢。我尝试了第一个awk脚本,它很有效。但是,似乎即使我给出了正确的标题,我也无法定义第一列……对不起,第三列中缺少一个空格在awk脚本中,匿名第一列被命名,修复了!非常感谢。我尝试了第一个awk脚本,它很有效。但是,似乎我可以