替换csv文件的多个值

Replace multiple value of csv file

我有一个 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 (=="1") ="22";if (=="2") ="35";if (=="3") ="14"} {print "\"""\""",""\"""\""",""\"""\""",""\"""\""}' /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

现在,命令 return :

awk -F , -v OFS=, '{if (=="1") ="2";if (=="2") ="3";if (=="3") ="5"} {print "\"""\""",""\"""\""",""\"""\""",""\"""\""}' 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 上的这个例子也有同样的问题。

使用 sed 可能更容易:

sed 's/\([0-9]*,[0-9]*,\)1\(,[0-9]*\)/2/' /tmp/test.csv
sed 's/\([0-9]*,[0-9]*,\)2\(,[0-9]*\)/5/' /tmp/test.csv
sed 's/\([0-9]*,[0-9]*,\)3\(,[0-9]*\)/4/' /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]*\)/2/' /tmp/test.csv
$ sed -i 's/\([0-9]*,[0-9]*,\)2\(,[0-9]*\)/5/' /tmp/test.csv
$ sed -i 's/\([0-9]*,[0-9]*,\)3\(,[0-9]*\)/4/' /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

None 您发布的代码在任何给定机器上与任何其他机器上的行为都不同。你说它确实如此并且最初发布错误代码是一个转移注意力的问题,你只是有错误代码,仅此而已。

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

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

假设您从输入文件中的 $3 开始,它的值为 1。您的第一个 test/assignment 是 if (=="1") ="2",因此在该代码执行后 $3 的值为 2。现在您的第二个 test/assignment 是 if (=="2") ="3" 那么,在您的第一个代码段执行后 $3 现在是 2,所以现在它设置为 3。然后您的下一个 test/assignment 将它设置为 5。

所以给定 $3 是 1,你将 $3 设置为 2,然后你将它设置为 3,然后你将它设置为 5 - 最终结果总是 5。投入一些 "else"s:

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

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

awk -F, -v OFS='","' '{if (=="1") ="2"; else if (=="2") ="3"; else if (=="3") ="5"} {print "\""[=12=]"\""}' 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)} {=m[]} {print "\""[=13=]"\""}' file
"9","9","2","2"
"10","10","3","2"
"13","13","5","2"

以上假设您的 3 美元始终是您 show/test 的价值之一。如果没有,可以进行简单的调整。

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

$ awk -F, -v OFS='","' 'BEGIN{split("1,2,3",a); split("2,3,5",b); for (i in a) m[a[i]]=b[i]} {=( in m ? m[] : )} {print "\""[=14=]"\""}' 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]} {=( in m ? m[] : )} {print "\""[=15=]"\""}' file
"9","9","2","2"
"10","10","3","2"
"13","13","5","2"