我有一个这种格式的文件:
a1,b1,c1,d1,e1,f1
a2,b2,c2,d2,e2,f2
我想在特定列周围添加引号 (")(例如 a 列和 d 列、列不要包含其他逗号,但它们的长度不同)以获得如下内容:
"a1",b1,c1,"d1",e1,f1
"a2",b2,c2,"d2",e2,f2
我尝试在多次迭代中执行类似下面的操作,将逗号 (,) 替换为逗号+引号 (,") 或引号+逗号 (",),具体取决于它是列的开头还是结尾:
sed -E 's/(([^,]*,){1}[^,]*),/\1\,\"/g'
但这会将每个第二个逗号替换为逗号和引号,而我希望每个命令仅控制一个添加引号的位置。
答案1
首先,您不希望g
,这意味着“全局”,替换所有出现的情况,并且由于您需要指定一列,因此您不想替换全部。接下来,您可以sed
像这样定位第 N 次出现:s/old/new/N
其中N
是第 N 次出现。因此,引用第四个字段,您可以这样做:
$ sed 's/[^,]*/"&"/4' file
a1,b1,c1,"d1",e1,f1
a2,b2,c2,"d2",e2,f2
并更改第一个字段:
$ sed 's/[^,]*/"&"/1' file
"a1",b1,c1,d1,e1,f1
"a2",b2,c2,d2,e2,f2
这&
是一个特殊sed
变量,表示“运算符左侧匹配的任何内容s///
”。
答案2
awk
对字段很好用(我自己不太好——这适用于字段 1 和 3,而不是 1 和 4)。
Awk='{
sub(/.*/, Dq "&" Dq, $1);
sub(/.*/, Dq "&" Dq, $3);
print;
}'
$ awk -v FS=, -v OFS=, -v Dq='"' "${Awk}" <<'[][]'
a1,b1,c1,d1,e1,f1
a2,b2,c2,d2,e2,f2
[][]
"a1",b1,"c1",d1,e1,f1
"a2",b2,"c2",d2,e2,f2
答案3
传递要引用的字段列表
awk -v fields='1,4' '
BEGIN {
FS = OFS = ","
n = split(fields, fs)
}
{ for (i=1; i<=n; i++) $(fs[i]) = "\"" $(fs[i]) "\"" }
{ print }
' file
"a1",b1,c1,"d1",e1,f1
"a2",b2,c2,"d2",e2,f2
答案4
使用awk
或磨坊主( mlr
),您要引用的字段编号在命令行上以逗号分隔的列表形式给出:
$ awk -F, -v f=1,4,5 'BEGIN { OFS=FS; split(f,a,",") } { for (i in a) $a[i] = "\"" $a[i] "\"" };1' file
"a1",b1,c1,"d1","e1",f1
"a2",b2,c2,"d2","e2",f2
$ mlr --nidx --fs comma put -s f=1,4,5 'begin { @a=splitnv(@f,",") } for (k,v in @a) { $[v] = "\"" . $[v] . "\"" }' file
"a1",b1,c1,"d1","e1",f1
"a2",b2,c2,"d2","e2",f2
两者在将输入视为一组逗号分隔记录的“简单 CSV”方面是等效的(没有字段嵌入分隔符或换行符)。
他们分割给定的数字字符串,其中每个数字对应于一个应该引用的字段。然后他们迭代这些字段并通过添加引号来修改每个字段。