我有三个文件,分别命名为a.csv
、b.csv
和c.csv
。
a.csv
有内容
1234567,11111111111111111111111111111111111111111111111111
b.csv
有类似的内容
1234567845610111211111111111111111111111111
c.csv
有内容
111111,22222222,3333333,,,44444444444444444444
从上面提到的三个文件中,我只需要a.csv
这意味着具有两列的文件不应包含任何空值,其余文件(b.csv
和c.csv
)必须加载到另一个List.txt
具有b.csv
和c.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
- 字段 2 为空
!$2
- 没有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
并假设既不能使用sed
也grep
不能使用并且您有数千每个文件的数量数千行很长,所以你只想检查每行的第一行,而不是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
-B1
ok.list
最后你可以使用ok.list
来过滤
ls *.csv | grep -Fvxf ok.list > banjaxed.list
您只需使用固定字符串(不是正则表达式)“-F”中的文件来grep
过滤掉文件,精确匹配仅使用文件作为要匹配的模式列表,当然,反转匹配最终重定向过滤后的文件列出至ok.list
ls
-x
-f
-v
banjaxed.list
如果那至少不值钱,那我就收拾我的玩具了。