如何按名称打印某些列?

如何按名称打印某些列?

我有以下文件:

id  name  age
1   ed    50
2   joe   70   

我只想打印idage列。现在我只使用awk

cat file.tsv | awk '{ print $1, $3 }'

然而,这需要知道列号。有没有办法可以使用列名(在第一行指定)而不是列号?

答案1

也许是这样的:

$ cat t.awk
NR==1 {
    for (i=1; i<=NF; i++) {
        ix[$i] = i
    }
}
NR>1 {
    print $ix[c1], $ix[c2]
}
$ awk -f t.awk c1=id c2=name input 
1 ed
2 joe
$ awk -f t.awk c1=age c2=name input 
50 ed
70 joe

如果你想指定在命令行上打印的列,你可以这样做:

$ cat t.awk 
BEGIN {
    split(cols,out,",")
}
NR==1 {
    for (i=1; i<=NF; i++)
        ix[$i] = i
}
NR>1 {
    for(i=1; i <= length(out); i++)
        printf "%s%s", $ix[out[i]], OFS
    print ""
}
$ awk -f t.awk -v cols=name,age,id,name,id input 
ed 1 ed 50 1 
joe 2 joe 70 2 

(注意-v用于获取块中定义的变量的开关BEGIN。)

答案2

csvkit

将输入数据转换为 csv 格式并使用 csv 工具,例如csvcut来自csvkit

$ cat test-cols.dat 
id  name  age
1   ed    50
2   joe   70 

安装 csvkit:

$ pip install csvkit

tr与其挤压选项一起使用-s,将其转换为有效的 csv 文件并应用csvcut

$ cat test-cols.dat | tr -s ' ' ',' | csvcut -c id,age
id,age
1,50
2,70

如果你想恢复到旧的数据格式,你可以使用tr ',' ' ' | column -t

$ cat test-cols.dat | tr -s ' ' ',' | csvcut -c id,age | tr ',' ' ' | column -t
id  age
1   50
2   70

笔记

  • csvkit 还支持不同的分隔符(共享选项 -d--delimiter),但返回 csv 文件:

    • 如果文件仅使用空格来分隔列(根本没有制表符),则以下工作

      $ csvcut -d ' ' -S -c 'id,age' test-cols.dat
      id,age
      1,50
      2,70
      
    • 如果文件使用制表符分隔列,则以下工作和csvformat可用于取回 tsv 文件:

      $ csvcut -t -c 'id,age' test-cols.dat | csvformat -T
      id  age
      1   50
      2   70
      

      据我检查,只允许使用一个选项卡。

  • csvlook可以将表格格式化为 Markdown 表格格式

    $ csvcut -t -c "id,age" test-cols.dat | csvlook
    | id | age |
    | -- | --- |
    |  1 |  50 |
    |  2 |  70 |
    
  • UUOC(无用的猫):我喜欢用这种方式构建命令。

答案3

只是将 Perl 解决方案扔进堆里:

#!/usr/bin/perl -wnla

BEGIN {
    @f = ('id', 'age');   # field names to print
    print "@f";           # print field names
}

if ($. == 1) {            # if line number 1
    @n = @F;              #   get all field names
} else {                  # or else
    @v{@n} = @F;          #   map field names to values
    print "@v{@f}";       #   print values based on names
}

答案4

物有所值。这可以处理源中任意数量的列,以及要打印的任意数量的列,无论您选择什么输出顺序;只需重新排列参数...

例如。称呼:script-name id age

outseq=($@)
colnum=($( 
  for ((i; i<${#outseq[@]}; i++)) ;do 
    head -n 1 file |
     sed -r 's/ +/\n/g' |
      sed -nr "/^${outseq[$i]}$/="
  done ))
tr ' ' '\t' <<<"${outseq[@]}"
sed -nr '1!{s/ +/\t/gp}' file |
  cut -f $(tr ' ' ','<<<"${colnum[@]}") 

输出

id      age
1       50
2       70

相关内容