删除 csv 文件中的多行

删除 csv 文件中的多行

我正在做这项任务,从包含不同客户的 CSV 文件中删除行。我已经弄清楚了如何使用以下代码删除一个特定的客户:

delete() {
  awk -F "\"*;\"*" '$1 != '$@' {print $ALL}' input.csv > output.csv
}

delete $@

但是,现在我必须同时删除多个客户。我可以通过存储在 csv 文件第一列中的客户编号来识别客户。我应该为不同的客户编号创建一个数组,并创建一个 while 循环来循环遍历该数组,但我似乎无法弄清楚。

答案1

我不确定你为什么要将它包装在 shell 函数中——我假设这是你任务的要求。

首先,请注意,"*;"*在 Awk 中用作字段分隔符并不是处理带引号的 CSV 字段的可靠方法 - 例如,如果一行中的第一个字段或最后一个字段被引号引起来,它就会失败,并且它不会保留带引号的分隔符(即,带引号的字段实际上包含;),这就错过了引用 CSV 字段的全部意义。

其次,您不应尝试以这种方式将 shell 变量(或位置参数)传递到 Awk 表达式中 - 正确的方法是导出它们,然后通过数组访问它们ENVIRON,或者使用命令行选项-v。因此,您的“单一客户”实现会写得更好

delcust() {
  awk -F '"*;"*' -v cust="$1" '$1 != cust' input.csv > output.csv
}
delcust "$1"

当你可以修改它以传递多个位置参数,我建议通过标准输入传递客户列表并将其解析为值文件;这样您就可以基于关联数组(或哈希)执行规范的 Awk 查找:

delcusts() {
  printf '%s\n' "$@" | awk -F'"*;"*' 'NR==FNR {custs[$0]=1; next} !($1 in custs)' - input.csv > output.csv
}
delcusts "$@"

请注意,您不需要print在 Awk 中显式指定,因为print如果规则评估结果为非零,则是默认操作。

答案2

实际上不需要数组。你可以像这样定义你的函数:

delete() {
  awk -v customer="^($1)\$" -F ";" '$1 !~ customer {print $ALL}' input.csv >output.csv 
}

我不明白您如何定义字段分隔符,因此我对其进行了更改以便能够进行测试。相关部分是使用否定正则表达式!~。此外,我还使用了-vawk 的参数,这可以为您省去很多 shell 引用的麻烦。

通过这个,您可以使用这样的参数来删除多个客户:

delete 'bla|foo'

对于 input.csv 这样的:

bla;blu;bli
foo;faa;fii
blafoo;blufaa;blifii

它会产生

blafoo;blufaa;blifii

在 output.csv 中。

如果您确实想使用数组,您可以另外定义一个小辅助函数来准备数组以供delete()上述函数使用:

join() { local IFS=\|; echo "$*"; }

通过它,您可以定义一个 bash 数组并将其转换为正则表达式替代语法:

$ a=(bla blu)
$ join ${a[@]}
bla|blu

然后你可以delete()像这样调用:

$ a=(customer1 customer2)
$ delete "$(join ${a[@]})"

(对于 zsh 用户的小提示:join()zsh 不需要该函数,您可以简单地使用以下参数扩展:${(j:|:)a}将所有数组元素与|字符连接起来)

相关内容