【问题标题】:Print column contents by column name按列名打印列内容
【发布时间】:2011-05-01 03:49:57
【问题描述】:

我想在 awk 或 cut 命令中输入一个字符串名称(即“COL2”)并打印与该列标题字符串匹配的列。

数据文件如下所示:

COL1 COL2 COL3 COL4 COL5 COL6
a a b d c f
a d g h e f
c v a s g a

如果我传入 COL3,我希望它打印第三列等。我认为 awk 可能是最容易使用的东西,但 cut 也可能有效。我只是不知道该怎么做。

【问题讨论】:

  • 好的,既然我们已经回答了你的问题,让我问一个问题:为什么不使用 cut(1)?
  • 我很想使用 cut。问题是我不知道如何匹配列名:-D。 cut -f $COLUMN_NAME 正在寻找一个数字,而不是要匹配的字符串...

标签: awk


【解决方案1】:

上述问题的 Awk 1 班轮(如果您有兴趣):

awk -v col=COL2 'NR==1{for(i=1;i<=NF;i++){if($i==col){c=i;break}} print $c} NR>1{print $c}' file.txt

awk -v col=COL3 'NR==1{for(i=1;i<=NF;i++){if($i==col){c=i;break}} print $c} NR>1{print $c}' file.txt

只需使用-vcol= 标志传递您的列名 COL1、COL2、COL3 等。

【讨论】:

  • 我很感兴趣。谢谢你的单线。但是它说“-v 是一个无效的选项”。不太确定该怎么做。编辑:当我在 -v 和 col 之间放置一个空格时它起作用了。非常精彩。谢谢!
  • 任何多列选项?
  • @lenzai:多列试试这个代码:awk -v col1=COL2 -v col2=COL6 'NR==1{for(i=1;i&lt;=NF;i++){if($i==col1)c1=i; if ($i==col2)c2=i;}} NR&gt;1{print $c1 " " $c2}' file.txt
  • @anubhava 应该如何修改后一个命令以便打印列名?所以COL2COL6。使用awk -v col=COL2 'NR==1{for(i=1;i&lt;=NF;i++){if($i==col){c=i;break}} print $c} NR&gt;1{print $c}' file.txt 会打印列名COL2
  • @anubhava 确实!这就是我所说的 ;)。我说它不适用于多列案例;)。无论如何,我相信答案是awk -v col1=h -v col2=N_bf 'NR==1{for(i=1;i&lt;=NF;i++){if($i==col1)c1=i; if ($i==col2)c2=i;} print $c1 " " $c2} NR&gt;1{print $c1 " " $c2}' file.txt。谢谢!
【解决方案2】:

对顶部的anubhava 帖子稍作修改, 多列

awk -vcol1="COL2" -vcol2="COL6" 'NR==1{for(i=1;i<=NF;i++){if($i==col1)c1=i; if ($i==col2)c2=i;}} NR>0{print $c1 " " $c2}' file.txt

当 NR>1 时不打印列标题。这已修改为 NR>0,它应该打印带有标题名称的列。

【讨论】:

    【解决方案3】:

    请注意,如果命名列不存在,第一个解决方案会打印出整个文件。如果发生这种情况,要输出警告消息,请尝试

    awk -v col=NoneSuch 'NR==1{for(i=1;i<=NF;i++){if($i==col){c=i;break}}   if (c > 0) {print $c}} else {print "Column " col "does not exist"} NR>1 && c > 0 {print $c}' file1.txt
    

    【讨论】:

      【解决方案4】:

      有点不清楚你要做什么。

      如果要从数据中获取单列,请使用substr()

      如果您想使用参数来选择列,请使用类似

      BEGIN { mycol = ARGV[1] ; }
            { print $mycol }
      

      更新

      嗯,所以你想要通用的列名?

      好的,我们假设您的数据是这样组织的:

       XXXXX YYYYY ZZZZZ
      

      并且您想将列命名为“harpo”、“groucho”和“zeppo”,列名在ARGV[1]

       BEGIN { cols["harpo"] = 1; cols["groucho"] = 2; cols["zeppo"] = 3; }
             { print $cols[ARGV[1]]   }
      

      第二次更新

      是的,这个技巧可以做到。将“harpo”等替换为“COL1”、“Col2”等。

      【讨论】:

      • 对列名进行硬编码并不是最佳选择,除非您知道它们一直是固定的。
      【解决方案5】:

      say column 是您声明的变量,它是您想要从 shell 获得的列。您使用 awk's -v 选项传递它

      column=3
      awk -vcol="$column" '{print $col}' file
      

      【讨论】:

        【解决方案6】:

        当你对 awk 说“传递一个字符串”时,我猜你想在命令行上给出这个字符串。一种选择是使用-v 功能来定义变量

        $ gawk -f columnprinter.awk -v col=thecolumnnameyouwant
        

        您也可以将内置变量ARGV 用作Charlie explains

        只剩下形成一个数组以将列名与列号相关联的问题。如果输入的第一行包含列名(通用约定),这将变得非常容易。

        使用

        NR==1{...}
        

        处理第一列得到映射

        NR==1{
           colnum=-1;
           for(i=1; i<=NF; i++)
             if ($i == col) {
                colnum=i
                break
             }
        }
        

        你可以像这样使用

        {
          print $colnum
        }
        

        【讨论】:

        • 这不是真的 - 只需使用 ARGV 和 ARGC 内置插件。
        • 这似乎不起作用。困难的部分是让 awk 匹配我输入的字符串...
        • @Charlie:Mea Culpa。我已经使用 awk 多年,但我从未真正“学习”过它。我只是在需要时阅读手册页。不知怎的,我错过了。
        • Nick columnprinter.awk 是您正在编写的脚本。或者你可以内联,但我猜这是你想要反复做的事情。
        猜你喜欢
        • 1970-01-01
        • 2014-05-20
        • 2019-10-27
        • 2015-06-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多