我想将第一行、第三行、第五行等所有字段中的值 3 和 4 分别替换为 0 和 1,直到以下数据集的末尾:
2 4 3 0
2 4 3 0
3 0 4 4
3 0 4 4
4 2 4 3
4 2 4 3
2 3 4 2
2 3 4 2
所以,期望的结果是:
2 1 0 0
2 4 3 0
0 0 1 1
3 0 4 4
1 2 1 0
4 2 4 3
2 0 1 2
2 3 4 2
我正在使用以下代码来执行此操作:
awk '{for (i = 1; i <= NR; i=(i+2))
if($i == 3) {$i = 0}
if($i == 4) {$i = 1}
}
END {print $0}' b.temp
但是,此代码的输出仅为 b.temp 文件最后一行中的值 (2 3 4 2)。
我怎样才能做到这一点?该代码需要针对任意数量的行和字段。解决方案可以是 awk、sed 或 shell 脚本中的其他替代方案。
提前致谢
答案1
使用 sed:
sed 'y/34/01/;n' file
意思是:
- 将这一行中的3和4替换为0和1并打印;
- 获取下一行并打印它;
- 获取下一行并重复循环。
但是,如果数据包含(例如 14),则将其转换为 11,这将失败。要解决此问题,请选择
sed 's/\<4\>/1/g;s/\<3\>/0/g;n' file
答案2
您的方法的问题在于您在块print
中只有一个语句END
。该块中的值$0
是文件最后一行的内容。因此,您的awk
代码只会打印文件的最后一行。
另请注意,将awk
操作应用于每行除非块之前有条件{ ... }
(例如END
仅适用于文件结尾)。所以,你的代码会尝试检查第一个、第三个等场地的每行如果是3
or分别用or4
替换...但永远不要打印结果。0
1
为了将规则应用于每个奇数行,您可以检查是否NR%2
为一(或简单地非零):
awk 'NR%2{for (i=1;i<=NF;i++) if ($i==3 || $i==4) $i-=3}1' b.temp
当1
出现在规则之外时, 是awk
“打印执行的所有转换所产生的行”的简写符号。
答案3
下面是我尝试的更优化的命令
命令
awk 'NR==1||NR==3||NR==5||NR==7{gsub("3","0",$0)}1' file | awk 'NR==1||NR==3||NR==5||NR==7{gsub("4","1",$0)}1'
输出
2 1 0 0
2 4 3 0
0 0 1 1
3 0 4 4
1 2 1 0
4 2 4 3
2 0 1 2
2 3 4 2