从csv中删除concret数据

时间:2015-03-29 10:45:48

标签: bash awk

我有一个包含5列的长csv文件。但是3行有6列。一个开始于" tomasluck",另一个" peterblack"最后一个" susanpeeters"。我需要在这3行中删除第四个元素(列)并且只获得5列。

我举了一个简短的例子,我的文件很长,是自动创建的。

petergreat, 15, 11-03-2015, 10, 10
tomasluck,  15, 10-03-2015, tl, 10, 10
anaperez,   14, 11-03-2015, 10, 11

我需要

petergreat, 15, 11-03-2015, 10, 10
tomasluck,  15, 10-03-2015, 10, 10
anaperez,   14, 11-03-2015, 10, 11

确切地说,我正在思考一个代码,选择以tomasluck,peterblack和susanpeeters开头的行,然后删除4rht字段或colum。

3 个答案:

答案 0 :(得分:2)

关于这一点的棘手问题是保持格式不变。我认为最简单的方法是将输入视为纯文本并使用sed:

sed '/^tomasluck,/ s/,[^,]*//3' file.csv

这将在以tomasluck,开头的行中删除第三次出现的逗号后跟字段(非逗号字符)。可以修改过滤器正则表达式以包括其他第一个字段,例如

sed '/^\(tomasluck\|petergreat\|anaperez\),/ s/,[^,]*//3' file.csv

...但在您的输入数据中,这些行似乎没有第六个字段。

可能与您的用例有关的其他想法:

基于字段数删除第四个字段在sed中有点棘手,主要是因为sed没有算术功能并且识别这些行有点乏味:

sed 'h; s/[^,]//g; /.\{5\}/ { x; s/,[^,]*//3; x; }; x' file.csv

那是:

h                # copy the line to the hold buffer
s/[^,]//g        # remove all non-comma characters
/.\{5\}/ {       # if five characters remain (if the line has six or more
                 # fields)
  x              # exchange pattern space and hold buffer
  s/,[^,]*//3    # remove field
  x              # swap back again
}
x                # finally, swap in the actual data before printing.

x舞是典型的使用保持缓冲区的sed脚本;目标是确保无论替换是否发生,最后都会打印出行(而不是孤立的逗号)。

请注意,如果您希望选择条件是一行有六个或更多字段,则值得考虑使用awk,其中条件更容易制定但是更换字段更繁琐:

awk -F , 'BEGIN { OFS = FS } NF > 5 { for(i = 5; i <= NF; ++i) { $(i - 1) = $i }; --NF; $1 = $1 } 1' file.csv

即:用逗号分隔行(-F ,),然后

BEGIN { OFS = FS }            # output field separator is input FS
NF > 5 {                      # if there are more than five fields
  for(i = 5; i <= NF; ++i) {  # shift them back one, starting at the fifth
    $(i - 1) = $i
  }
  --NF                        # let awk know that there is one less field
  $1 = $1                     # for BSD awk: force rebuilding of the line
}
1                             # whether or not a transformation happened, print.

这适用于大多数问题;我用gawk和mawk测试了它。但是,因为没有什么比这更容易移植,我被告知至少有一个awk(在旧的Solaris上,我相信)不理解--NF技巧。有可能与sprintf一起破解某些东西,但这已经足够我不希望它咬你了。

答案 1 :(得分:1)

更通用的解决方案是检查我们是否有5个或6个字段:

awk -F', ' '{if(NF==6) print $1", "$2", "$3", "$5", "$6; else print $0}' file.csv

答案 2 :(得分:0)

你可以通过sed使用捕获组基于正则表达式的捕获组来完成此任务。

$ sed 's/^\(\(tomasluck\|peterblack\|susanpeeters\),[^,]*,[^,]*\),[^,]*/\1/' file
petergreat, 15, 11-03-2015, 10, 10
tomasluck,  15, 10-03-2015, 10, 10
anaperez,   14, 11-03-2015, 10, 11

这会捕获第三列之前的所有字符并匹配第四列。用匹配组1中的字符替换匹配的字符将为您提供所需的输出。