更新 Shell 中特定列的分隔符

Update Delimiter of Specific Columns in Shell

我有一个CSV文件,CSV文件的列数是10。但是有一列包含","这个值。我想将文件的分隔符更改为 "|" 而不更改包含 " 的列中的数据,"

我有文件

John Doe,19,England,3653,Manchester, England,Main Worker,20-05-1995

Bill Mark,19, Australia,3653,Main Street, People Two, Perth,Main Worker,20-05-1995

Mark Home,19,USA,3653, Redmond, Ground Town, Main Street, Virginia,Main Worker,20-05-1995

需要输出

John Doe|19|England|3653|Manchester, England|Part Time Worker|20-05-1995

Bill Mark|19|Australia|3653|Main Street, People Two, Perth|Main Worker,20-05-1995

Mark Home|19|USA|3653| Redmond, Ground Town, Main Street, Virginia|Main Worker|20-05-1995

我尝试了多种解决方案,但无法实现我想要的。我尝试了以下命令,它只更新前 4 列的分隔符。

sed 's/,/|/;s/,/|/;s/,/|/;s/,/|/' file

我正在寻找的方法是更新前 4 列和后 2 列的分隔符。通过这种方式,我可以获得带有更新分隔符的文件,并且地址列对其没有影响。

使用 sed (GNU sed) 4.7 :

sed 's/, /\o0/g;s/,/|/g;s/\d0/, /g' file

您文件中的字段分隔符是逗号,但有些字段可以包含逗号。
正如您在数据中看到的那样,字段中的逗号永远不会单独出现。
幸运的是它后面总是有一个space。
所以首先,将 ', ' 转换为 char NUL (\o0)。这个字符永远不会出现在文本文件中。
之后,将所有逗号转换为'|'
最后,恢复 ', '

或者,对于 GNU Awk 5.1.0,API:3.0(GNU MPFR 4.1.0、GNU MP 6.2.1)

awk -F', ' 'BEGIN{OFS=FS}{for(i=1;i<=NF;i++)gsub(",","|",$i)}1' file

你可以使用awk。这种脚本可以完成工作:

t='John Doe,19,England,3653,Manchester, England,Main Worker,20-05-1995'
echo $t | awk '{ORS="";N=split([=10=],a,",");\
            print a[1]"|"a[2]"|"a[3]"|"a[4]"|"; \
            for(i=5;i<N-1;i++) print a[i]; 
            print "|"a[N-1]"|"a[N] }'

从给出的简单示例来看,您要保留的逗号是唯一后跟 spaces 的逗号。

$: cat foo
Name,Age,Country,ID,Address,Category,DOB
John Doe,19,England,3653,Manchester, England,Main Worker,20-05-1995
Bill Mark,19, Australia,3653,Main Street, People Two, Perth,Main Worker,20-05-1995
Mark Home,19,USA,3653, Redmond, Ground Town, Main Street, Virginia,Main Worker,20-05-1995

$: sed -E 's/,(\S)/|/g' foo
Name|Age|Country|ID|Address|Category|DOB
John Doe|19|England|3653|Manchester, England|Main Worker|20-05-1995
Bill Mark|19, Australia|3653|Main Street, People Two, Perth|Main Worker|20-05-1995
Mark Home|19|USA|3653, Redmond, Ground Town, Main Street, Virginia|Main Worker|20-05-1995

这会扫描后跟 NONspace 的逗号,并记住后面的字符。
它将匹配的逗号(和下面保存的字符)替换为竖线(和下面保存的字符)。它将忽略后跟 space 的逗号,因为它们与模式不匹配。

这仍然适用于所有提供的示例。
对于逗号后没有 space 的情况,您将不得不重建该行。

$: cat foo
Name,Age,Country,ID,Address,Category,DOB
John Doe,19,England,3653,Manchester, England,Part Time Worker,20-05-1995
Bill Mark,19, Australia,3653,Main Street, People Two, Perth,Main Worker,20-05-1995
Mark Home,19,USA,3653, Redmond, Ground Town, Main Street, Virginia,Main Worker,20-05-1995

$: cat tst
while IFS=, read -a line;                                  # read and split
do set -- "${line[@]}"                                     # set as , etc
   for i in 0 1 2 3; do printf "%s|" ""; shift;  done;   # print first 4
   while (( 3 < $# )); do printf "%s, " ""; shift; done  # all BUT last 3
   printf "%s|" "" ""                                  # last 2 get |
   echo ""                                               # last 1 gets \n
done<foo

$: ./tst
Name|Age|Country|ID|Address|Category|DOB
John Doe|19|England|3653|Manchester,  England|Part Time Worker|20-05-1995
Bill Mark|19| Australia|3653|Main Street,  People Two,  Perth|Main Worker|20- 05-1995
Mark Home|19|USA|3653| Redmond,  Ground Town,  Main Street,  Virginia|Main Worker|20-05-1995

请注意,这样做会保留字段中的前导 space。如果你想删除那些你需要手动完成,但是你可以一次性完成整个文件:

sed -E 's/[|]\s+/\|/g' file 

如果你真的想 trim 所有领域都 leading/trailing 白色 space -

sed -E 's/^\s+//; s/\s+[|]\s+/\|/g; s/\s+$//;' file 

例如:

$: ./tst|    sed -E 's/[|]\s+/\|/g'
Name|Age|Country|ID|Address|Category|DOB
John Doe|19|England|3653|Manchester,  England|Part Time Worker|20-05-1995
Bill Mark|19|Australia|3653|Main Street,  People Two,  Perth|Main Worker|20-05-1995
Mark Home|19|USA|3653|Redmond,  Ground Town,  Main Street,  Virginia|Main Worker|20-05-1995