验证shell中列的唯一值

时间:2018-01-19 13:05:38

标签: bash shell unique cut

我得到一个输入文件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。

3 个答案:

答案 0 :(得分:3)

尝试awk命令,这是非常精炼的。

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

其他方式::

我们可以逐行分配所有零售商ID,例如retailer.txtretailer.txt的内容就像

a
b

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

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

答案 1 :(得分:1)

或许这样的事情?

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

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

awk 'NR==FNR { ++a[$1] }'的一般模式是将一组文件中的第一个读入内存中的数组的常用方法,然后在脚本的其余部分执行某种类型的连接(在数据库意义上)其他输入文件中的字段。 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处理标准输入(在这种情况下来自管道)

答案 2 :(得分:-1)

grep无法做你想做的事情吗?

如果我理解,使用正确的正则表达式在您的csv文件上调用grep可以使用错误的零售商打印所有行。 你需要选择一个强大的正则表达式以防止误报,但我需要输入示例来帮助你......

或者,如果正则表达式不能防止误报,你可以使用grep after cut命令,如下所示:

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

带有坏零售商的名字。

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