无法区分 unix 脚本主题中的有效文件和无效文件

无法区分 unix 脚本主题中的有效文件和无效文件

我有三个文件,分别命名为a.csvb.csvc.csv

a.csv有内容

1234567,11111111111111111111111111111111111111111111111111

b.csv有类似的内容

1234567845610111211111111111111111111111111

c.csv有内容

111111,22222222,3333333,,,44444444444444444444

从上面提到的三个文件中,我只需要a.csv这意味着具有两列的文件不应包含任何空值,其余文件(b.csvc.csv)必须加载到另一个List.txt具有b.csvc.csv文件的文本文件示例中。

我尝试过下面的命令来删除不带逗号(,)的文件,即b.csv,但我需要考虑c.csv以及无效

grep -v "," *.csv |cut -d ":" -f1 

按照建议,我尝试了下面的命令,它可以显示具有两列值的文件

awk -F"," 'NF==2 {print FILENAME}' *.csv

但我也需要将无效文件写入另一个文件中,请给我一些建议。

根据建议尝试了以下但没有成功

ls | grep -v $(awk -F"," 'NF==2 {print FILENAME}') *.csv|sort -u

我也被建议尝试

awk -F',' 'BEGINFILE{ok=1}!$1||!$2||NF!=2{ok=0; nextfile}ENDFILE{if(!ok)print FILENAME}' *.csv

但这会导致以下错误:

awk: A statement occurred that is not valid.

 The input line number is 1. The file is <Filename>
 The source line number is 1.

请注意,我的第二个字段值的长度为 250 个字符,并且有 n 个类似于a.csv, b.csv...

答案1

如果我理解正确,您想要丢弃包含满足以下任一条件的任何行的任何文件:

  1. 字段 1 为空!$1
  2. 字段 2 为空!$2
  3. 没有2个字段NF!=2

然后

awk -F',' 'BEGINFILE{ok=1}!$1||!$2||NF!=2{ok=0; nextfile}ENDFILE{if (ok) print FILENAME}' *.csv

它只是设置ok=1标志,然后循环遍历每一行,直到上述任何条件为真,并且一旦发现“坏”行,就会使文件无效ok=0并跳到文件末尾而不解析更多行nextfile

在每个文件的末尾,ENDFILE它只打印FILENAME何时if (ok)非零

因此,要否定匹配,只需将最后一个测试反转为if (!ok)打印即可

awk -F',' 'BEGINFILE{ok=1}!$1||!$2||NF!=2{ok=0; nextfile}ENDFILE{if (!ok) print FILENAME}' *.csv

编辑

我无法在我的输出中重现失败gawk(请参见下文,包括将文件名重定向到 xxx.file)

bash --version
GNU bash, version 5.0.16(1)-release (x86_64-pc-linux-gnu)

awk --version
GNU Awk 5.1.0, API: 3.0 (GNU MPFR 4.0.2, GNU MP 6.2.0)

tail -n +1 *.csv; 
  awk -F',' 'BEGINFILE{ok=1}
    !$1||!$2||NF!=2{ok=0; nextfile}
  ENDFILE{gzout=(ok)?"ok":"banjaxed"; print FILENAME > gzout".files"}' *.csv ; 
tail -n +1 *.files

==> a.csv <==
1234567,11111111111111111111111111111111111111111111111111

==> b.csv <==
1234567845610111211111111111111111111111111

==> c.csv <==
111111,22222222,3333333,,,44444444444444444444

==> banjaxed.files <==
b.csv
c.csv

==> ok.files <==
a.csv

单个字段长度限制 (1024)不应该是一个问题除非awk您突破 3,000 个字符的记录限制,在这种情况下,似乎awk都不sed是完成这项工作的工具。

答案2

作为替代方法,使用grep并假设既不能使用sedgrep不能使用并且您有数千每个文件的数量数千行很长,所以你只想检查每行的第一行,而不是grep一路 ping 它们......

获取所有第一行(带有文件名)并将它们放入文件中

head -n1 *.csv > list

每个条目都有一行上下文(文件名),第一行和后面的空行,如下所示

==> a.csv <==
1234567,11111111111111111111111111111111111111111111111111

==> b.csv <==
1234567845610111211111111111111111111111111

你知道符合线条的模式是^[0-9.]+,[0-9.]+$,所以你可以

grep -E -B1 "^[0-9]+,[0-9]+$" list | grep -oP "(?<= )[^, <]+" > ok.list

第一个从之前的一行上下文grep中提取匹配项(包含匹配的文件名),第二个提取文件名并将它们转储到您想要的文件中list-B1ok.list

最后你可以使用ok.list来过滤

ls *.csv | grep -Fvxf ok.list > banjaxed.list

您只需使用固定字符串(不是正则表达式)“-F”中的文件来grep过滤掉文件,精确匹配仅使用文件作为要匹配的模式列表,当然,反转匹配最终重定向过滤后的文件列出至ok.listls-x-f-vbanjaxed.list

如果那至少不值钱,那我就收拾我的玩具了。

相关内容