我有以下列表:
COX1
COX1
COX1
COX1
COX1
Cu-oxidase
Cu-oxidase_3
Cu-oxidase_3
Fer4_NifH
我要搜索列表中是否有COX1
和Cu-oxidase
,我想打印xyz
,如果Cu-oxidase_3
和Fer4_NifH
在也是列表(如果前两个在列表中是独立的,那么它应该打印abc
。
这是我到目前为止的脚本:
if grep 'COX1' file.txt; then echo xyz; else exit 0; fi
但它当然是不完整的。 任何解决方案?
理想情况下,我的输出是:
xyz
abc
答案 0 :(得分:0)
Awk可让您轻松搜索多个正则表达式,并打印除匹配字符串本身以外的其他内容。 (grep
也可以轻松搜索多个模式,但它会打印匹配或其行号或文件名,而不是一些任意字符串。)
以下假设您每行都有一个令牌。这个假设使脚本非常简单,但支持其他场景也不难。
awk '{ a[$1]++ }
END { if (("COX1" in a) && ("Cu-oxidase" in a)) print "xyz";
if (("Cu-oxidase_3" in a) && ("Fer4_NifH" in a)) print "abc" }' file.txt
这构建了每个标记的关联数组(实际上是每行上第一个以空格分隔的标记),然后在最后,当它读取文件中的每一行时,检查所寻找的标记是否作为数组中的键存在
对输入文件执行单次传递是一项重大胜利,尤其是如果您有大量输入文件和许多模式。为了完整起见,使用grep
执行多次传递的语法非常简单;
if grep -qx 'COX1' file.txt && grep -qx 'Cu-oxidase' file.txt
then
echo xyz
fi
可以进一步缩写为
grep -qx 'COX1' file.txt && grep -qx 'Cu-oxidase' file.txt && echo xyz
注意-x
开关要求整行匹配(否则正则表达式'Cu-oxidase'
也会匹配 Cu-oxidase_3 行。
答案 1 :(得分:-1)
以上是实现这一目标的非常冗长的方式。有一些方法可以用较少的if
和更少的grep
来编写相同的内容,但我真的想向您展示逻辑:
运行grep命令,使用$?
检查其返回值,最后根据条件执行操作。
# default values
HAS_COX1=0
HAS_CUOX=0
HAS_CUO3=0
HAS_FER4=0
# run silently grep
grep -q 'COX1' file.txt
# check for return value and set variable accordingly
if [ $? -eq 0 ]; then HAS_COX1=1; fi
# same as above
grep -q 'Cu-oxidase' file.txt
if [ $? -eq 0 ]; then HAS_CUOX=1; fi
grep -q 'Cu-oxidase_3' file.txt
if [ $? -eq 0 ]; then HAS_CUO3=1; fi
grep -q 'Fer4_NifH' file.txt
if [ $? -eq 0 ]; then HAS_FER4=1; fi
if [ $HAS_COX1 -eq 1 ]; then
if [ $HAS_CUOX -eq 1 ]; then
echo 'xyz'
exit 0
fi
fi
if [ $HAS_CUO3 -eq 1 ]; then
if [ $HAS_FER4 -eq 1 ]; then
echo 'abc'
exit 0
fi
fi
echo 'None of the checks where matched'
exit 1
注意:此代码未经测试,因此可能存在错误☺
代码并不完美,因为当满足这两个条件时,它无法同时打印'xyz'
和'abc'
(但这可以通过我提供的语法轻松修复)。每当找到$HAS_CUOX
时,1
也会设置为$HAS_CUO3
(grep
正则表达式中没有边界检查)。
您可以使用单个grep为每组条件进行检查,使用'COX1\|Cu_oxidase'
作为grep的正则表达式来进一步获取该代码。并解决了我上面提到的小问题。
理想情况下,我的输出将是:
xyz
abc
在我编写完上述脚本后添加了您的预期输出,但考虑到我给你的元素,你应该能够想出如何改进它(基本上删除放置它们的exit 0
,然后执行{ {1}}当没有给出输出时。
或者只删除所有exit 1
作为脏解决方案。