替换csv文件的多个值

时间:2016-04-25 14:40:10

标签: bash ubuntu awk debian

我有一个csv文件:

1,1,1,2
2,2,1,2
3,3,1,2
4,4,1,2
5,5,1,2
6,6,1,2
7,7,1,2
8,8,1,2
9,9,1,2
10,10,2,2
11,11,2,2
12,12,2,2
13,13,3,2

我想将每个第三个值替换为: 如果1;然后22 如果2;然后35 如果3;然后14

这就是我所做的:

awk -F , -v OFS=, '{if ($3=="1") $3="22";if ($3=="2") $3="35";if ($3=="3") $3="14"} {print "\""$1"\""",""\""$2"\""",""\""$3"\""",""\""$4"\""}' /tmp/test.csv

它在Debian上工作得很好但在Ubuntu上却没有。 问题是什么 ?谢谢你

[编辑] 我昨天引用的例子可行,但不适用于此: cat -v test.csv

1,1,1,2
2,2,1,2
3,3,1,2
4,4,1,2
5,5,1,2
6,6,1,2
7,7,1,2
8,8,1,2
9,9,1,2
10,10,1,2
11,11,1,2
12,12,1,2
13,13,1,2
14,14,1,2
15,15,1,2
16,16,1,2
17,17,1,2
18,18,1,2
19,19,1,2
20,20,1,2
21,21,1,2
22,22,1,2
23,23,1,2
24,24,1,2
25,25,1,2
26,26,1,2
27,27,1,2
28,28,1,2
29,29,1,2
30,30,1,2
31,31,1,2
32,32,1,2
33,33,1,2
34,34,1,2
35,35,1,2
36,36,1,2
37,37,1,2
38,38,1,2
39,39,1,2
40,40,1,2

现在,命令返回:

awk -F , -v OFS=, '{if ($3=="1") $3="2";if ($3=="2") $3="3";if ($3=="3") $3="5"} {print "\""$1"\""",""\""$2"\""",""\""$3"\""",""\""$4"\""}' toast.csv
"1","1","5","2"
"2","2","5","2"
"3","3","5","2"
"4","4","5","2"
"5","5","5","2"
"6","6","5","2"
"7","7","5","2"
"8","8","5","2"
"9","9","5","2"
"10","10","5","2"
"11","11","5","2"
"12","12","5","2"
"13","13","5","2"
"14","14","5","2"
"15","15","5","2"
"16","16","5","2"
"17","17","5","2"
"18","18","5","2"
"19","19","5","2"
"20","20","5","2"
"21","21","5","2"
"22","22","5","2"
"23","23","5","2"
"24","24","5","2"
"25","25","5","2"
"26","26","5","2"
"27","27","5","2"
"28","28","5","2"
"29","29","5","2"
"30","30","5","2"
"31","31","5","2"
"32","32","5","2"
"33","33","5","2"
"34","34","5","2"
"35","35","5","2"
"36","36","5","2"
"37","37","5","2"
"38","38","5","2"
"39","39","5","2"
"40","40","5","2"

所有第三个值都等于5而不是2.在Debian上这个例子的问题相同。

2 个答案:

答案 0 :(得分:1)

您发布的任何代码在任何给定计算机上与任何其他计算机的行为都不同。你说这样做并且最初发布了错误的代码是一个红色的鲱鱼,你只是有错误的代码,这就是全部。

您在最新编辑中添加的代码表示:

if ($3=="1") $3="2";if ($3=="2") $3="3";if ($3=="3") $3="5"

所以,让我们假设您从输入文件中的$ 3开始,其值为1.您的第一个测试/分配是if ($3=="1") $3="2"所以在该代码执行后$ 3有值2.现在您的第二个测试/赋值是if ($3=="2") $3="3"好了,你的第一个代码段执行后$ 3 IS现在是2,所以现在它被设置为3.然后你的下一个测试/赋值将它设置为5.

因此,给定3美元即1,你将3美元设置为2,然后将其设置为3然后将其设置为5 - 净结果是它始终为5.投入一些"否则&# 34,S:

if ($3=="1") $3="2"; else if ($3=="2") $3="3"; else if ($3=="3") $3="5"

但至少要更改脚本以避免必须单独打印每个字段:

awk -F, -v OFS='","' '{if ($3=="1") $3="2"; else if ($3=="2") $3="3"; else if ($3=="3") $3="5"} {print "\""$0"\""}' toast.csv

并考虑使用更惯用的方法:

$ cat file
9,9,1,2
10,10,2,2
13,13,3,2

$ awk -F, -v OFS='","' 'BEGIN{split("2,3,5",m)} {$3=m[$3]} {print "\""$0"\""}' file
"9","9","2","2"
"10","10","3","2"
"13","13","5","2"

以上假设您的$ 3始终是您展示/测试的值之一。如果没有那么简单的调整。

通常将一组任意数字映射到另一组,并允许一些不需要映射的输入数据:

$ awk -F, -v OFS='","' 'BEGIN{split("1,2,3",a); split("2,3,5",b); for (i in a) m[a[i]]=b[i]} {$3=($3 in m ? m[$3] : $3)} {print "\""$0"\""}' file
"9","9","2","2"
"10","10","3","2"
"13","13","5","2"

或者如果您愿意:

$ awk -F, -v OFS='","' 'BEGIN{split("1,2,2,3,3,5",t); for (i=2;i in t;i+=2) m[t[i-1]]=t[i]} {$3=($3 in m ? m[$3] : $3)} {print "\""$0"\""}' file
"9","9","2","2"
"10","10","3","2"
"13","13","5","2"

答案 1 :(得分:0)

使用sed可能更容易:

sed 's/\([0-9]*,[0-9]*,\)1\(,[0-9]*\)/\122\2/' /tmp/test.csv
sed 's/\([0-9]*,[0-9]*,\)2\(,[0-9]*\)/\135\2/' /tmp/test.csv
sed 's/\([0-9]*,[0-9]*,\)3\(,[0-9]*\)/\114\2/' /tmp/test.csv

我认为应该这样做,并且最有可能适用于大多数sh / bash环境。

编辑: 请注意,这只是打印出每个命令所做的实际替换,因此您知道在实际更改任何内容之前会发生什么。您可能需要先备份文件,然后使用-i标志进行替换:

$ cat /tmp/test.csv
1,1,1,2
2,2,1,2
3,3,1,2
4,4,1,2
5,5,1,2
6,6,1,2
7,7,1,2
8,8,1,2
9,9,1,2
10,10,2,2
11,11,2,2
12,12,2,2
13,13,3,2
$ cp /tmp/test.csv /tmp/test.csv.bak
$ sed -i 's/\([0-9]*,[0-9]*,\)1\(,[0-9]*\)/\122\2/' /tmp/test.csv
$ sed -i 's/\([0-9]*,[0-9]*,\)2\(,[0-9]*\)/\135\2/' /tmp/test.csv
$ sed -i 's/\([0-9]*,[0-9]*,\)3\(,[0-9]*\)/\114\2/' /tmp/test.csv
$ cat /tmp/test.csv
1,1,22,2
2,2,22,2
3,3,22,2
4,4,22,2
5,5,22,2
6,6,22,2
7,7,22,2
8,8,22,2
9,9,22,2
10,10,35,2
11,11,35,2
12,12,35,2
13,13,14,2