我有一个非常简单的问题。我有一个包含多个列的文件,我想使用awk过滤它们。
所以感兴趣的列是第6列,我想找到包含以下内容的每个字符串:
所以每个例子:20S50M没问题
我试过了:
awk '{ if($6 == '/[1-100][S|M][1-100][S|M]/') print} file.txt
但它不起作用......我做错了什么?
答案 0 :(得分:37)
这应该可以解决问题:
awk '$6~/^(([1-9]|[1-9][0-9]|100)[SM]){2}$/' file
Regexplanation:
^ # Match the start of the string
(([1-9]|[1-9][0-9]|100) # Match a single digit 1-9 or double digit 10-99 or 100
[SM] # Character class matching the character S or M
){2} # Repeat everything in the parens twice
$ # Match the end of the string
你的陈述有很多问题:
awk '{ if($6 == '/[1-100][S|M][1-100][S|M]/') print} file.txt
==
是字符串比较运算符。正则表达式比较运算符为~
。awk
引用任何带引号的内容)并且你的脚本缺少最后的(合法)< / em>单引号。 [0-9]
是数字字符的字符类,它不是数字范围。这意味着匹配类0,1,2,3,4,5,6,7,8,9
中的任何字符,而不是范围内的任何数值,因此[1-100]
不是数字范围1 - 100中的数字的正则表达式,它将匹配1或0 。[SM]
相当于(S|M)
您尝试的内容[S|M]
与(S|\||M)
相同。您不需要字符类中的OR运算符。 使用以下结构condition{action}
进行awk。如果条件为True,则对正在读取的当前记录执行以下块{}
中的操作。我的解决方案中的条件是$6~/^(([1-9]|[1-9][0-9]|100)[SM]){2}$/
,可以读取第六列与正则表达式匹配,如果为True则打印行,因为如果您没有得到任何操作,则awk
将执行{{ 1}}默认情况下。
答案 1 :(得分:2)
我会将正则表达式检查和数字验证作为不同的步骤。此代码适用于GNU awk:
$ cat data
a b c d e 132x123y
a b c d e 123S12M
a b c d e 12S23M
a b c d e 12S23Mx
我们希望只有第3行通过验证
$ gawk '
match($6, /^([[:digit:]]{1,3})[SM]([[:digit:]]{1,3})[SM]$/, m) &&
1 <= m[1] && m[1] <= 100 &&
1 <= m[2] && m[2] <= 100 {
print
}
' data
a b c d e 12S23M
为了可维护性,您可以将其封装到函数中:
gawk '
function validate6() {
return( match($6, /^([[:digit:]]{1,3})[SM]([[:digit:]]{1,3})[SM]$/, m) &&
1<=m[1] && m[1]<=100 &&
1<=m[2] && m[2]<=100 );
}
validate6() {print}
' data
答案 2 :(得分:1)
正则表达式无法检查数值。 “1到100之间的数字”超出了正则表达式的范围。您可以做的是检查“1-3位数”。
你想要这样的东西
/\d{1,3}[SM]\d{1,3}[SM]/
请注意,字符类[SM]
没有!
替换字符。如果您将其写为(S|M)
,则只需要这样做。
答案 3 :(得分:1)
编写您发布的脚本的方法:
awk '{ if($6 == '/[1-100][S|M][1-100][S|M]/') print} file.txt
在awk中所以它会做你想要做的事情:
awk '$6 ~ /^(([1-9][0-9]?|100)[SM]){2}$/' file.txt
发布一些样本输入和预期输出,以帮助我们为您提供更多帮助。
答案 4 :(得分:0)
试试这个:
awk'$ 6~ / ^([1-9] | 0 [1-9] | [1-9] [0-9] | 100)+ [S | M] +([1-9] | 0 [1-9] | [1-9] [0-9] | 100)+ [S | M] $ /'file.txt
由于您没有准确说明第6列中的格式如何,以上内容适用于列为“03M05S”,“40S100M”或“3M5S”的位置;并排除所有其他。例如,它不会找到'03F05S','200M05S','03M005S,003M05S或'003M005S'。
如果你可以在0-99时将第6列中的数字保持为2,或者在准确为100时将3中的数字保持为 - 这意味着当低于10时正好是一个前导零,否则没有前导零,那么这是一个更简单的匹配。您可以使用上述模式但排除单个数字(删除第一个[1-9]条件),例如
awk'$ 6~ / ^(0 [1-9] | [1-9] [0-9] | 100)+ [S | M] +(0 [1-9] | [1-9] [0-9] | 100)+ [S | M] $ /'file.txt
答案 5 :(得分:0)
我知道该线程已经得到解答,但是实际上我有一个类似的问题(与查找“使用查询”的字符串有关)。我正在尝试对字符'S','M','I','=','X','H'之类的字符之前的所有整数求和,以通过对端找到读取长度读取CIGAR字符串。
我编写了一个Python脚本,该脚本从SAM / BAM文件中获取$ 6列:
import sys # getting standard input
import re # regular expression module
lines = sys.stdin.readlines() # gets all CIGAR strings for each paired-end read
total = 0
read_id = 1 # complements id from filter_1.txt
# Get an int array of all the ints matching the pattern 101M, 1S, 70X, etc.
# Example inputs and outputs:
# "49M1S" produces total=50
# "10M757N40M" produces total=50
for line in lines:
all_ints = map(int, re.findall(r'(\d+)[SMI=XH]', line))
for n in all_ints:
total += n
print(str(read_id)+ ' ' + str(total))
read_id += 1
total = 0
read_id的目的是将您正在经历的每个读取标记为“唯一”,以防您要获取read_lengths并将其打印在BAM文件的awk-ed列旁边。
我希望这可以帮助或至少帮助下一个遇到类似问题的用户。 我咨询了https://stackoverflow.com/a/11339230供参考。