AWK if子句组合字段

时间:2016-10-06 16:52:28

标签: awk

我有一个制表符分隔文件,其中包含> 10,000行,每行可变数量的列数(33-35)。

对于有34列的行,我想将第3-4列折叠为一个:

col1    col2    col3    col4   ...   col34
index1  tool     kit    math         new

到 - >

col1   col2    col3   ...   col33
index1 tool    kit;math     new

同样,对于35列,我想将第3-5列折叠成一列。我的预感是,可能有一种方法可以利用AWK和NF来实现这一目标。任何提示或帮助?

4 个答案:

答案 0 :(得分:0)

你可以通过在给定两个或三个条件的情况下使用for循环遍历字段来缩短它,但是长手(对于awk新手来说更容易理解)是:

awk 'NF==35{print $1,$2,$3$4$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$30,$31,$32,$33,$34,$35} NF==34{print $1,$2,$3$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$30,$31,$32,$33,$34} NF==33{$1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$30,$31,$32,$33}' yourfile.txt

这是一个满口的,但它只是根据记录中的字段数打印出不同的字段组合。

答案 1 :(得分:0)

这是另一个awk,具有更大的灵活性。我改用了5-7列。

$ cat file
col1    col2    col3    col4    col5
1       2       3       4       5       6
1       2       3       4       5
1       2       3       4       5       6       7

$ awk -v OFS='\t' 'NR==1{print; next} 
                    NF>5{$3=$3 $4; t=1} 
                    NF>6{$3=$3 $5; t=2} 
                       t{for(i=4;i<=NF;i++) $i=$(i+t);
                         NF=NF-t; t=0}1' file

col1    col2    col3    col4    col5
1       2       34      5       6
1       2       3       4       5
1       2       345     6       7

答案 2 :(得分:0)

在awk中:

NF>5 {                                         # if more than 5 (33) fields
    for(i=(NF-5)-1; i>=0; i--)                 # execute next for once or twice
        for(j=3+i; j<=NF; j++)                 
            $j=( j<4+i ? $j ";" : "" ) $(j+1)  # catenate once or twice on i
    NF=5 
} $1=$1                                        # is this a problem?

运行它:

$ awk -v OFS='\t' -f program.awk karakfa\'s.txt
col1    col2    col3    col4    col5
1       2       3;4     5       6
1       2       3       4       5
1       2       3;4;5   6       7

答案 3 :(得分:0)

在某些TXR

awk paradigm实施了270 lines of TXR Lisp

预热:整个文件中的基本列合并:

$ txr -e '(awk ((>= nf 4) (set [f 2..4] (list `@[f 2];@[f 3]`)))
               (t))'
1
1
1 2
1 2
1 2 3
1 2 3
1 2 3 4
1 2 3;4
1 2 3 4 5
1 2 3;4 5

字段是列表f,而不是涉及美元符号的特殊语法小工具,因此它们易受切片分配的影响:(set [target-sequence n..m] source-sequence)替换n..m切片(来自{{ 1 {} nmm target-sequence之外的source-sequence。索引是从零开始的,所以要替换第三个和第四个字段,我们表示切片2..4:即索引2和3,不包括4。

(t)是一个没有条件的条件 - 操作条款,类似于Awk&#39; 1:它触发隐式(prn)形式,打印rec(相当于$0); t是一个自我评估的符号,它规范地表示布尔值为true,但nil以外的任何值都为真。当以某种方式操纵f时,例如通过上面的切片分配,rec会自动从字段重新构建,方法是在它们之间插入ofs,就像在Awk Classic中填充字段一样重组$0

现在,如何将第一行作为要打印的标题处理然后忽略:

$ txr -e '(awk ((= nr 1) (prn) (next))
               ((>= nf 4) (set [f 2..4] (list `@[f 2];@[f 3]`)))
               (t))'
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 3 3;4 5

接下来,我们要求改变34对35的范围。我们如何使用条件&#34; 34或更多列&#34;。可以通过更改表达式来处理移位范围:

[f 2..4]

[f (if (> nf 34) 2..5 2..4))]

但是如果我们将条件范围绑定到变量然后在几个地方使用它,我们可以以统一的方式完成它。我们只需要测试一次条件。结果是:

$ txr -e '(awk ((= nr 1) (prn) (next))
               ((>= nf 4) (let ((r (if (> nf 34) 2..5 2..4)))
                            (set [f r] (list `@{[f r] ";"}`))))
               (t))'
col1 col2 ...
col1 col2 ...
1 2 3 4 5 6 7 8 9 0 A B C D E F G H I J K L M N O P Q R S T U V W X Y
1 2 3;4;5 6 7 8 9 0 A B C D E F G H I J K L M N O P Q R S T U V W X Y
1 2 3 4 5 6 7 8 9 0 A B C D E F G H I J K L M N O P Q R S T U V W X
1 2 3;4 5 6 7 8 9 0 A B C D E F G H I J K L M N O P Q R S T U V W X

在反引号分隔的准字符串文字中,语法@{[seq range] string}将使用字符串作为分隔符插入序列的一个片段。我们只是插入范围r,它与我们删除的范围相同,并替换为结果字符串;我们有条件地根据我们是否有超过34列来切换r,因此测试仅在一次,并且r在两个地方使用。