【问题标题】:grep, cut, sed, awk a file for 3rd column, n lines at a time, then paste into repeated columns of n rows?grep,cut,sed,awk 一个文件用于第三列,一次 n 行,然后粘贴到 n 行的重复列中?
【发布时间】:2014-08-01 19:15:24
【问题描述】:

我有一个格式如下的文件:

#some header text
a    1       1234
b    2       3333
c    2       1357

#some header text 
a    4       8765
b    1       1212
c    7       9999
...

在 n 行块中包含由空行分隔的重复数据(可能还有其他一些标题文本)。我只对第三列感兴趣,想做一些 grep, cut, awk, sed, paste 魔法把它变成这样:

a   1234    8765   ...
b   3333    1212
c   1357    9999

其中每个后续 n 行块的第三列被添加为新列。我想你可以称之为转置,一次只有 n 行,只有一个特定的列。前导 (a b c) 列标签不是必需的...如果我能抓取第三列中的数据,我会很高兴

这甚至可能吗?一定是。我可以使用 grep 和 cut 将内容缩减为仅有趣的列:

cat myfile | grep -A2 ^a\  | cut -c13-15

但我不知道如何将这些 n 行块和 sed/粘贴/无论它们放入重复的 n 行列中。

有什么想法吗?

【问题讨论】:

标签: regex bash awk sed


【解决方案1】:

这个awk 完成了这项工作:

awk 'NF<3 || /^(#|[[:blank:]]*$)/{next} !a[$1]{b[++k]=$1; a[$1]=$3; next} 
        {a[$1] = a[$1] OFS $3} END{for(i=1; i<=k; i++) print b[i], a[b[i]]}' file
a 1234 8765
b 3333 1212
c 1357 9999

【讨论】:

  • 如果有超过 a b c ?
  • OP 写道:The leading (a b c) column label isn't essential... I'd be happy if I could just grab the data in the third column
  • 好的。那么你有我的 +1
  • 你是个 awk 巫师!这工作得很好,而且通常(我的实际测试文件比 (a b c) 示例更混乱。非常感谢。
【解决方案2】:
awk '/#/{next}{a[$1] = a[$1] $3 "\t"}END{for(i in a){print i, a[i]}}' file

会产生

a 1234  8765
b 3333  1212
c 1357  9999

如果愿意,您可以将 "\t" 更改为不同的输出分隔符,例如 " "

sub(/\t$/, "", a[i]); 可以插入到printif 之前,如果您不喜欢尾随空格。另一种解决方案是检查a[$1] 是否已经有一个值,您可以在其中决定是否附加到先前的值。虽然它使代码有点复杂。

【讨论】:

    【解决方案3】:

    使用 bash > 4.0:

    declare -A array
    while read line
    do
       if [[ $line && $line != \#* ]];then
           c=$( echo $line | cut -f 1 -d ' ')
           value=$( echo $line | cut -f 3 -d ' ')
           array[$c]="${array[$c]} $value"
       fi
    done < myFile.txt
    
    for k in "${!array[@]}"
    do
        echo "$k ${array[$k]}"
    done
    

    将产生:

    a  1234 8765
    b  3333 1212
    c  1357 9999
    

    它将字母存储为关联数组的键,并在每次迭代中将对应的值附加到它。

    【讨论】:

      【解决方案4】:
      $ awk -v RS= -F'\n' '{ for (i=2;i<=NF;i++) {split($i,f,/[[:space:]]+/); map[f[1]] = map[f[1]] " " f[3]} } END{ for (key in map) print key map[key]}' file
      a 1234 8765
      b 3333 1212
      c 1357 9999
      

      【讨论】:

        猜你喜欢
        • 2018-10-10
        • 1970-01-01
        • 1970-01-01
        • 2013-12-27
        • 2020-03-09
        • 1970-01-01
        • 2019-10-09
        • 1970-01-01
        • 2018-06-01
        相关资源
        最近更新 更多