Awk 如何根据模式更改行上字符串的顺序?

Awk 如何根据模式更改行上字符串的顺序?,awk,sed,grep,Awk,Sed,Grep,我有包含数据的文件,但有些行的数据顺序错误: name cat value 7.25 label X value 1.13 label 2 value 15.75 label 1 name dog label 1 value 20.00 label X value 9.00 label 2 value 1.10 name cow value 1.10 label 2 value 8.25 label X value 19.00 label 1 name sheep value 1.1

我有包含数据的文件,但有些行的数据顺序错误:

name cat
value 7.25 label X
value 1.13 label 2
value 15.75 label 1  
name dog
label 1 value 20.00
label X value 9.00
label 2 value 1.10  
name cow
value 1.10 label 2
value 8.25 label X
value 19.00 label 1  
name sheep
value 1.11 label 2
value 8.80 label X
value 19.00 label 1  
name mouse
value 1.13 label 2
value 8.00 label X
value 19.00 label 1  
name donkey
value 1.05 label 2
value 9.50 label X
value 16.00 label 1  
name dog
label 1 value 20.00
label X value 9.00
label 2 value 1.10  
如您所见,有些行以label*开头,有些行以value*开头, 我希望在行以“value”开头时交换字符串的顺序,以便所有行(忽略包含名称的行)都采用此格式
“Label*value*”

期望输出:

name cat
label X value 7.25
label 2 value 1.13
label 1 value 15.75  
name dog
label 1 value 20.00
label X value 9.00
label 2 value 1.10  
name cow
label 2 value 1.10
label X value 8.25
label 1 value 19.00 
name sheep
label 2 value 1.11
label X value 8.80
label 1 value 19.00  
name mouse
label 2 value 1.13
label X value 8.00
label 1 value 19.00  
name donkey
label 2 value 1.05
label X value 9.50
label 1 value 16.00  
name dog
label 1 value 20.00
label X value 9.00
label 2 value 1.10  
我尝试过编写一个循环,对以“value”开头的行进行grepping,但是我不确定接下来的步骤


我怎样才能做到这一点呢?

这份工作非常适合
awk

awk '$1 == "value" { print $3, $4, $1, $2; next; } 1'
awk
程序由条件/操作对组成;只有当
$1==“value”
为true时,才运行第一个块中的代码,在这种情况下反转操作;
1
是一个裸条件(因此获得打印整行的默认操作,该操作在第一个条件未运行时运行(其
next
命令导致流控制直接跳到输入的下一行)。

类似以下内容:

sed 's/^\(label .* \)\(value .*\)/\2 \1/'
此解决方案需要gawk(gnu awk)而不是传统的awk。如下所示:

BEGIN {
        IGNORECASE = 1;
    }
    {
        if( match( $0, \
          /value[[:space:]]+([0-9\.]+)[[:space:]]+label[[:space:]]+([0-9A-Z]+)/,
          groups ) )
          printf( "label %s value %s\n", groups[2], groups[1]);
        else
          print $0;
    }

<查尔斯>的答案对这个问题很有好处,但是如果在其他更复杂的上下文中有标签值对,那么首先要创建的是这些对的数组,然后用它们的标签/名称来打印它们:

$ awk '
    function p(tag) { return (tag OFS f[tag]) }
    NF==4 { for (i=1;i<NF;i+=2) f[$i]=$(i+1); $0=p("label") OFS p("value") }
1' file
name cat
label X value 7.25
label 2 value 1.13
label 1 value 15.75
name dog
label 1 value 20.00
label X value 9.00
label 2 value 1.10
name cow
label 2 value 1.10
label X value 8.25
label 1 value 19.00
name sheep
label 2 value 1.11
label X value 8.80
label 1 value 19.00
name mouse
label 2 value 1.13
label X value 8.00
label 1 value 19.00
name donkey
label 2 value 1.05
label X value 9.50
label 1 value 16.00
name dog
label 1 value 20.00
label X value 9.00
label 2 value 1.10
$awk'
函数p(tag){return(tagofsf[tag])}

NF==4{(i=1;iYou最近似乎在做相当多的文本文件操作,因此请务必阅读并注意,发明shell的人也发明了awk,以便在需要进行一般文本操作时调用。记住这一点,并在这里看到您的答案,您将理解为什么
编写循环,并对以w开头的行进行greppingith“value”
永远不会仅仅是操作文本的正确起点。这将在修改后的行末尾留下空白,可能是
sed-E的/^(label.*)*(value.*/\2\1/'文件