我正在尝试找到一种方法,使用 awk/sed 过滤 csv 以截断特定列(例如第 1 列)中的值,以保留最后 8 个字符并用通配符替换开头,前提是其他两个特定列不是等于 NULL - 例如第 3 列和第 5 列
示例数据:
1597012957a0dg9a0t593qa_filename1.exe,NULL,NULL,DATA,NULL,DATA
asvasihtiqsafsoithqwtoihwoi_filename2.exe,NULL,DATA,DATA,DATA,DATA
会成为:
1597012957a0dg9a0t593qa_filename1.exe,NULL,NULL,DATA,NULL,DATA
*.filename2.exe,NULL,DATA,DATA,DATA,DATA
我使用一系列的 pippingrev
和编写了这个脚本cut
,但效率非常低,而且我正在学习更高级awk
/sed
过滤器,因为我正在处理大量数据,并且脚本需要几个小时。
答案1
awk -v c=8 'BEGIN{ FS=OFS="," }
$3!="NULL" && $5!="NULL"{ $1=(length($1)>c?"*"substr($1,length($1)-c+1):$1) }1' infile
在这里,仅当列#1 的长度> 8 个字符(您可以更改c=#
要保留的字符数)时,我们才添加“*”,否则打印列#1 不变。
答案2
使用perl:
- 替换第一个字段中直到
_
字符、逻辑 AND (&&
) 的所有内容 - 即两者都不能为“NULL”:
$ perl -F, -pe 's/^.*?_/*/ if ($F[2] ne "NULL" && $F[4] ne "NULL")' input.csv
1597012957a0dg9a0t593qa_filename1.exe,NULL,NULL,DATA,NULL,DATA
*filename2.exe,NULL,DATA,DATA,DATA,DATA
asvasihtiqsafsoithqwtoihwoi_filename2.exe,NULL,NULL,DATA,DATA,DATA
asvasihtiqsafsoithqwtoihwoi_filename2.exe,NULL,DATA,DATA,NULL,DATA
这使用了 perl 的“非贪婪”?
量词 with ,.*
以便它只匹配第一个(大概是唯一的)下划线字符。
- 替换第一个字段中直到
_
字符、逻辑或 (||
) 的所有内容,即其中一个或两个都不能为“NULL”:
$ perl -F, -pe 's/^.*?_/*/ if ($F[2] ne "NULL" || $F[4] ne "NULL")' input.csv
1597012957a0dg9a0t593qa_filename1.exe,NULL,NULL,DATA,NULL,DATA
*filename2.exe,NULL,DATA,DATA,DATA,DATA
*filename2.exe,NULL,NULL,DATA,DATA,DATA
*filename2.exe,NULL,DATA,DATA,NULL,DATA
- 替换第一个字段除最后 8 个字符之外的所有字符,逻辑 AND:
$ perl -F, -pe 's/^.*?(.{8}),/*$1,/ if ($F[2] ne "NULL" && $F[4] ne "NULL")' input.csv
1597012957a0dg9a0t593qa_filename1.exe,NULL,NULL,DATA,NULL,DATA
*ame2.exe,NULL,DATA,DATA,DATA,DATA
asvasihtiqsafsoithqwtoihwoi_filename2.exe,NULL,NULL,DATA,DATA,DATA
asvasihtiqsafsoithqwtoihwoi_filename2.exe,NULL,DATA,DATA,NULL,DATA
这使用捕获组(.{8})
来提取第一个字段的最后 8 个字符,并将它们用于替换字符串 ( $1
)。
- 替换第一个字段除最后 8 个字符之外的所有字符,逻辑或:
$ perl -F, -pe 's/^.*?(.{8}),/*$1,/ if ($F[2] ne "NULL" || $F[4] ne "NULL")' input.csv
1597012957a0dg9a0t593qa_filename1.exe,NULL,NULL,DATA,NULL,DATA
*ame2.exe,NULL,DATA,DATA,DATA,DATA
*ame2.exe,NULL,NULL,DATA,DATA,DATA
*ame2.exe,NULL,DATA,DATA,NULL,DATA
- 替换除最后 8 个字符之外的所有字符基本名称文件名的一部分(即“扩展名”之前),逻辑 AND。
$ perl -F, -pe 's/^.*?(.{8})\./*$1./ if ($F[2] ne "NULL" && $F[4] ne "NULL")' input.csv
1597012957a0dg9a0t593qa_filename1.exe,NULL,NULL,DATA,NULL,DATA
*ilename2.exe,NULL,DATA,DATA,DATA,DATA
asvasihtiqsafsoithqwtoihwoi_filename2.exe,NULL,NULL,DATA,DATA,DATA
asvasihtiqsafsoithqwtoihwoi_filename2.exe,NULL,DATA,DATA,NULL,DATA
注意:文件名“扩展名”在 unix 和 linux 文件系统中并不那么重要。此外,它们并不像古老的 MS-DOS FAT 文件系统那样限制为 3 个字符,而且可以有多个字符 - 现代 Windows 文件系统也是如此。如果文件名.
中包含多个字符,则此版本将无法按照您的预期工作。
- 现在逻辑“或”版本应该很明显了。
注意:perl 数组从 0 开始,而不是 1。这就是为什么第三个字段在 中$F[2]
,第五个字段在 中$F[4]
。
另外,我在示例输入中添加了两行,以显示使用 AND 和 OR 之间的区别。
$ cat input.csv
1597012957a0dg9a0t593qa_filename1.exe,NULL,NULL,DATA,NULL,DATA
asvasihtiqsafsoithqwtoihwoi_filename2.exe,NULL,DATA,DATA,DATA,DATA
asvasihtiqsafsoithqwtoihwoi_filename2.exe,NULL,NULL,DATA,DATA,DATA
asvasihtiqsafsoithqwtoihwoi_filename2.exe,NULL,DATA,DATA,NULL,DATA
输入的第三行和第四行与您的第二行相同,只是在第3行,字段3中的“DATA”已更改为“NULL”,在第4行,字段5中的“DATA”已更改为“无效的。
答案3
#!/usr/bin/python
import re
k=open('filepath','r')
for i in k:
kospl=i.strip().split(',')
if (kospl[2] != "NULL" and kospl[4] != "NULL" and kospl[0] >8):
lk=len(kospl[0])-13
k="*."+kospl[0][lk:]+","
print k+",".join(kospl[1:])
else:
print i.strip()
~
输出
1597012957a0dg9a0t593qa_filename1.exe,NULL,NULL,DATA,NULL,DATA
*.filename2.exe,NULL,DATA,DATA,DATA,DATA