原始文件如下所示:
stat.sn 15094 291 usf=630 ind=32615 on_2=ON-14-6003 spd=307 i_pow=150
stat.sn 15094 361 usf=630 ind=32658 spd=307 i_pow=150
stat.sn 15094 360 usf=630 ind=32658 spd=307 i_pow=150
stat.sn 15094 272 usf=630 ind=32615 on_2=ON-14-6003 spd=307 i_pow=150
stat.sn 15094 276 usf=630 ind=32615 on_2=ON-14-6003 spd=307 i_pow=150
我需要它像这样:
stat.sn 15094 291 usf=630 ind=32615 spd=307 i_pow=150 on_2=ON-14-6003
stat.sn 15094 361 usf=630 ind=32658 spd=307 i_pow=150
stat.sn 15094 360 usf=630 ind=32658 spd=307 i_pow=150
stat.sn 15094 272 usf=630 ind=32615 spd=307 i_pow=150 on_2=ON-14-6003
stat.sn 15094 276 usf=630 ind=32615 spd=307 i_pow=150 on_2=ON-14-6003
简单地说:如果on_2存在于一行中,它应该是一行中的最后一个值。 其余值的顺序应保持不变。
如果存在,则on_2始终为第6个字段 - 在 ind 之后和 spd 之前。所有字段在每一行中都具有相同的位置。
我想awk可以实现这一点,但无法弄清楚如何做到这一点。
答案 0 :(得分:2)
所以你想在匹配时最后移动$ 6列。
awk '$6 ~ /^on_2/ { t=$6; $6=$7; $7=$8; $8=t } 1' file
如果匹配模式可能存在于任何列中,我们希望始终在最后打印它。
awk '{
for(i=1;i<NF-1;i++)
if($i~/^on_2/) {
t=$i;
for(j=i;j<NF;j++)
$j=$(j+1);
$NF=t
}
} 1' file
我们可以通过设置t=$i; $i=""
和打印$0 t
来省略此转变,但随后会在移动列的位置打印额外的FS,从而打破对齐。
更新:了解如何使用$(NF+1)=i; $i=""
并保留对齐方式,请检查此answer。
答案 1 :(得分:2)
简单地说:如果on_2存在于一行中,它应该是a中的最后一个值 行。其余值的顺序应保持不变。
获得所需输出的更多方法,无论on_2存在于何处,搜索,提取,无效并将其作为最后一列:
$ awk 'match($0,/on_2=[^ ]* /){s=substr($0,RSTART,RLENGTH);sub(s,"");$0=$0 FS s}1' infile
stat.sn 15094 291 usf=630 ind=32615 spd=307 i_pow=150 on_2=ON-14-6003
stat.sn 15094 361 usf=630 ind=32658 spd=307 i_pow=150
stat.sn 15094 360 usf=630 ind=32658 spd=307 i_pow=150
stat.sn 15094 272 usf=630 ind=32615 spd=307 i_pow=150 on_2=ON-14-6003
stat.sn 15094 276 usf=630 ind=32615 spd=307 i_pow=150 on_2=ON-14-6003
<强>解释强>
awk 'match($0,/on_2=[^ ]* /){ # Search
s=substr($0,RSTART,RLENGTH); # if found extract it
sub(s,""); # remove extracted part from row
$0=$0 FS s # set extracted part at the end
}1 # print line/record
' infile
match($0,/on_2=[^ ]* /)
- 在记录/行/行中搜索regexp(on2=[^ ]*
)
/on_2=[^ ]* /
on_2=
字面匹配字符on_2=
(区分大小写)[^ ]*
*
量词 - 在零和无限次之间匹配,尽可能多次,根据需要回馈(贪婪)
字面匹配字符(区分大小写) s=substr($0,RSTART,RLENGTH);
如果匹配则从记录中提取字符串,并将其保存在变量s
sub(s,"")
- 在s中搜索字符串,在记录/行中,用null替换
$0=$0 FS s
- 修改记录/行/行
}1
- 1
最后执行默认操作,即打印当前/记录/行,print $0
。要知道awk如何工作,请尝试awk '1' infile
,它将打印所有记录/行,而awk '0' infile
则不打印任何内容。除零以外的任何数字都是 true ,这会触发默认行为。
答案 2 :(得分:1)
请问您可以尝试关注并告诉我这是否对您有帮助(GNU sed
)。
sed -r 's/( on_2=[^ ]+)(.*)/\2\1/' Input_file
输出如下。
stat.sn 15094 291 usf=630 ind=32615 spd=307 i_pow=150 on_2=ON-14-6003
stat.sn 15094 361 usf=630 ind=32658 spd=307 i_pow=150
stat.sn 15094 360 usf=630 ind=32658 spd=307 i_pow=150
stat.sn 15094 272 usf=630 ind=32615 spd=307 i_pow=150 on_2=ON-14-6003
stat.sn 15094 276 usf=630 ind=32615 spd=307 i_pow=150 on_2=ON-14-6003
如果要将输出作为制表符空格分隔。
sed -r 's/( on_2=[^ ]+)(.*)/\2\1/' Input_file | column -t
答案 3 :(得分:1)
另一个sed
$ sed -r 's/(\son_2=\S+)(.*)/\2\1/' file
stat.sn 15094 291 usf=630 ind=32615 spd=307 i_pow=150 on_2=ON-14-6003
stat.sn 15094 361 usf=630 ind=32658 spd=307 i_pow=150
stat.sn 15094 360 usf=630 ind=32658 spd=307 i_pow=150
stat.sn 15094 272 usf=630 ind=32615 spd=307 i_pow=150 on_2=ON-14-6003
stat.sn 15094 276 usf=630 ind=32615 spd=307 i_pow=150 on_2=ON-14-6003
答案 4 :(得分:1)
$ awk '$6 ~ /^on_2=/{$(NF+1)=$6; $6=""; $0=$0; $1=$1}1' file
stat.sn 15094 291 usf=630 ind=32615 spd=307 i_pow=150 on_2=ON-14-6003
stat.sn 15094 361 usf=630 ind=32658 spd=307 i_pow=150
stat.sn 15094 360 usf=630 ind=32658 spd=307 i_pow=150
stat.sn 15094 272 usf=630 ind=32615 spd=307 i_pow=150 on_2=ON-14-6003
stat.sn 15094 276 usf=630 ind=32615 spd=307 i_pow=150 on_2=ON-14-6003
为什么格式化需要$0=$0; $1=$1
:
$6=""
将foo<blank>$6<blank>bar
更改为foo<blank><blank>bar
,即在$ 6现在为空之前和之后留空,且字段数不变,$ 5仍为foo
而7美元仍是bar
。
然后使用$0=$0
导致awk将$0
重新拆分为字段,因此foo和bar之间的多个空格被视为单个fied分隔符,所以尽管$ 5仍然是foo,现在$ 6是酒吧和那里的线上少了1个。 $ 0仍然包含foo和bar之间的2个空格,但由于这并没有改变$ 0,它只是改变了它被分成单个字段分配的方式。
然后使用$1=$1
(或分配给任何字段)会导致awk使用字段之间的OFS值(空白字符)重新编译$ 6,所以在此之后foo和bar之间只有1个空白2。
因此$ 0 = $ 0为$ 1&gt; $ NF创建新值,$ 1 = $ 1会导致它们之间的所有FS被OFS替换。