假设我有一个很长的文件,其中包含物种及其出现情况。我想保留其中一些发生的物种,就我而言:CHU、NEU、RNE、SCR、TDF。比如我原来的矩阵是:
Species_A; CHU, NEU, TUC, SCR
Species_B; CHU, NEU, RNE, SCR, TDF
Species_C; COR, NEU, SAL, TDF
Species_D; CHU, RNE, SCR, TDF
Species_D; SCR, TDF
我想只保留那些出现过 CHU、NEU、RNE、SCR、TDF 的物种,同时排除其余站点:
Species_B; CHU, NEU, RNE, SCR, TDF
Species_D; CHU, RNE, SCR, TDF
Species_D; SCR, TDF
我认为一种选择可能是:
awk -F “;” '$2/CHU/&&/NEU/&&/RNE/&&/SCR/&&/TDF/{ print}' 文件
但这也包括那些不需要的网站(例如 SAL、TUC)。
欢迎任何提示。
最佳答案
awk方法1:正则表达式
$ awk '/;([[:blank:],]*(CHU|NEU|RNE|SCR|TDF))+$/' file
Species_B; CHU, NEU, RNE, SCR, TDF
Species_D; CHU, RNE, SCR, TDF
Species_D; SCR, TDF
这仅打印那些与正则表达式 ;([[:blank:],]*(CHU|NEU|RNE|SCR|TDF))+$
匹配的行。
awk 方法 2:循环
尝试:
$ awk '{for (i=2;i<=NF;i++) if (!($i~/^(CHU|NEU|RNE|SCR|TDF)/)) next} 1' file
Species_B; CHU, NEU, RNE, SCR, TDF
Species_D; CHU, RNE, SCR, TDF
Species_D; SCR, TDF
它是如何工作的
for (i=2;i<=NF;i++) if (!($i~/^(CHU|NEU|RNE|SCR|TDF)/)) next
这会循环第一个单词之后的所有单词。如果这些单词中的任何一个不是以您批准的 3 字母字符串之一开头,那么我们将跳过其余命令并跳转到
next
重新开始。线。1
这是 awk 的 print-the-line 的简写。 (当然,只有当上面的
next
命令没有被触发时才会执行。)
使用 sed
使用与方法 1 相同的逻辑:
$ sed -En '/;([[:blank:],]*(CHU|NEU|RNE|SCR|TDF))+$/p' file
Species_B; CHU, NEU, RNE, SCR, TDF
Species_D; CHU, RNE, SCR, TDF
Species_D; SCR, TDF
使用 grep
使用相同的正则表达式逻辑:
$ grep -E ';([[:blank:],]*(CHU|NEU|RNE|SCR|TDF))+$' file
Species_B; CHU, NEU, RNE, SCR, TDF
Species_D; CHU, RNE, SCR, TDF
Species_D; SCR, TDF
关于unix - 使用 awk 选择特定单词,同时忽略其他单词,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48857694/