使用awk,有没有一种简单的方法可以用空格对字段进行分组

时间:2020-03-27 04:35:57

标签: awk

我有一个文件,其数据如下:

New York  100 2 17 12
California 200 10 8 3
Montana   50 25  3 0

我希望将状态名称视为一个字段,然后计算字段2占字段3的百分比,并忽略其他字段。

所以我希望输出是

New York  2%
California 5%
Montana   50%

这样我就可以获得州名awk -F [0-9] '{print $1}'

,但是其余字段完全不可用。

如果我不理会字段分隔符,New和York将获得单独的字段编号,而其他字段编号则“相距一”。

我可以用awk做到这一点,还是应该切换到我知道一点的红宝石?

3 个答案:

答案 0 :(得分:1)

您可以将最后一个字段用作参考点。需要gawk / mawk丢弃最后四个字段:

$ awk '{p=$(NF-2)*100/$(NF-3); NF-=4; print ($0"\t"p"%")}' file
New York   2%
California 5%
Montana    50%

便携式替代品是:

awk '{p=$(NF-2)*100/$(NF-3); sub(/( +[^ ]+){4}$/,""); print ($0"\t"p"%")}' file

答案 1 :(得分:1)

您可以在awk中轻松地做到这一点。诀窍是找到第一个以数字开头的字段,以便您可以容纳"New York"之类的名称。例如

awk '{
    n=0; name=""
    for(i=1;i<=NF;i++)
        if($i ~ /^[0-9]/) {
            n=i; break
        }
        else
            name=name?name" "$i:$i
    print name, $(n+1)/$n*100"%"
}' file

其中变量n用于通过在每个字段上循环并将第一个字符与[0-9]进行比较来捕获以数字开头的第一个字段的字段号。如果测试为真,则将n设置为i并中断循环,否则将字符字段与name串联。(假设您有2个带数字的字段)< / p>

您只需选择复制上面的脚本,然后将鼠标中键粘贴到保存文件的目录中的xterm中(更改文件名以匹配数据文件之后),将其与数据放在一起,将得到:

$ awk '{
>     n=0; name=""
>     for(i=1;i<=NF;i++)
>         if($i ~ /^[0-9]/) {
>             n=i; break
>         }
>         else
>             name=name?name" "$i:$i
>     print name, $(n+1)/$n*100"%"
> }' file
New York 2%
California 5%
Montana 50%

答案 2 :(得分:0)

假设最后总是有固定数量的字段,那么您可以根据以下记录使用该信息即时调整字段:

pax> echo; printf 'New York 100 2 17 12\nCalifornia 200 10 8 3\nMontana 50 25 3 0\n' | awk '
+++> {while(NF>5){$1=$1" "$2;for(i=2;i<NF;i++){$i=$(i+1)};$NF="";NF=NF-1};print $1","$2","$3","$4}'

New York,100,2,17
California,200,10,8
Montana,50,25,3

通过,分隔符,您可以看到字段1已从两个字段NewYork中合并。详细检查该脚本:

while (NF > 5) {                 # Loop until entire name combined into field 1.
    $1 = $1" "$2                 # Join field 1 and 2.
    for (i = 2; i < NF; i++) {   # For every field 2 onward.
        $i = $(i+1)              # Copy following field to this field,
    }                            #     includes blanking last field.
    NF = NF - 1                  # Reduce field count.
}
# At this point field1 is whole name and fields 2-5 are values.