验证 shell 中列的唯一值

Validating unique values of a column in shell

我得到一个输入文件 vendor.csv,其中有一个名为 retailer 的列。 我有一个预定义的有效零售商值列表,它们是 a、b、c。如果 'd' 出现在零售商栏中,我将不得不采取一些行动,主要是将其回显到日志中并停止处理并通知用户。

到目前为止我已经完成了以下操作

f1=/stage/Scripts/ecommerce/vendor/final*.csv
k=`cut -d, -f1 $f1 |sort -u`
echo $k

这给了我

a b c d

上面的o/p不是逗号分隔的

对于上述情况,我可以将有效值 a b c 存储在文件或字符串中

我现在如何进行支票?这是解决此问题的最佳方法吗

有效值为 ALB/SFY Total Ecom TA Peapod Total Ecom TA Target Total Ecom TA

现有数据包含以下唯一数据点 ALB/SFY Total Ecom TA Hy-Vee Total Ecom TA Peapod Total Ecom TA Target Total Ecom TA

因此 "Hy-Vee Total Ecom TA" 是一个无效值。

这是我对 grep 的尝试

$ echo $s
ALB/SFY Total Ecom TA Peapod Total Ecom TA Target Total Ecom TA

 echo $k
ALB/SFY Total Ecom TA Hy-Vee Total Ecom TA Peapod Total Ecom TA Target Total Ecom TA

grep -v "$s" "$k"

它给了我一个错误

grep: ALB/SFY Total Ecom TA
Hy-Vee Total Ecom TA
Peapod Total Ecom TA
Target Total Ecom TA: No such file or directory

一些解决方案为我指出了正确的方法,在 R 中,我将以

的形式完成上述任务
valid_values = ['a','b','c']
invalid_retailer = unique(vendorfile$retailer) %not% in valid_values 

我试图在 shell 中复制相同的过程,因此我使用了 cut 和 grep。

grep不能如愿以偿?

据我所知,使用正确的正则表达式对您的 csv 文件调用 grep 可以打印出错误零售商的所有行。 您需要选择一个强大的正则表达式来防止误报匹配,但我需要输入示例来帮助您...

或者,如果正则表达式无法防止误报,您可以在 cut 命令后使用 grep,如下所示:

for bad_retailer in $(cut -d, -f1 $f1 | grep d) ; do echo $bad_retailer ; done

with d 坏零售商的名字。

如果您想跟踪 1 个以上的不良零售商,您可以使用 grep -E "d|g|h",不良零售商的名称为 d、g 和 h。

也许是这样的?

awk -F, 'NR==FNR { ++a[]; next }
    !a[] { print FILENAME ":" FNR ": Invalid label "  >>"/dev/stderr" }' valid.txt final*.csv

其中 valid.txt 包含您的有效标签,每行一个。

awk 'NR==FNR { ++a[] }' 的一般模式是将一组文件中的第一个文件读入内存中的数组,然后在脚本的其余部分执行某种连接(在数据库意义上) 与其他输入文件中的字段。 awk 一次只处理一行,因此其他文件实际上可以任意大。不过,您确实需要能够将第一个文件中的数据存储在内存中。

与您的基本 cut+grep 尝试相比的优势在于我们可以打印整个输入行,而不是仅仅告诉您哪些标签无效然后让您返回并手动找出哪些文件实际包含违规的行。

顺便说一下,您的 grep 尝试有很多问题。首先,如果您处理的不仅仅是玩具数据,您希望避免将数据存储在 shell 变量中。其次,您可能想要调整您的选项以告诉 grep 您想要按字面匹配文本(-F - 没有这个,a.c 匹配 abc 因为点是例如,正则表达式通配符)并且您希望匹配覆盖整行(-x——没有这个,b 匹配 abc,因为它是一个子字符串)。

cut -d, -f1 final*.csv | sort -u |
grep -vxFf valid.txt

-f filename 选项表示从文件中读取模式,并且没有另一个文件名,grep 处理标准输入(来自管道,在这种情况下)。

试试 awk 命令,它精炼多了。

awk -F',' '{if (( == "a") || ( == "b") || ( == "c") || ( == "d")) print [=10=] }' /stage/Scripts/ecommerce/vendor/final*.csv

Other way::

我们可以在单独的文件中逐行给出所有零售商 ID,例如 retailer.txtretailer.txt的内容就像

a
b

为了打印与 retailer.txt 中的零售商 ID 匹配的那些行的第一个字段(由 , 分隔),请使用以下命令:

awk -F',' 'FNR==NR{=a[];next} ( in a)' retailer.txt final*.csv