我有一个很简单的问题。我有一个包含几列的文件,我想使用 awk 过滤它们。
所以感兴趣的列是第 6 列,我想找到包含的每个字符串:
- 从 1 到 100 的数字开始
- 在那个“S”或“M”之后
- 又是一个从 1 到 100 的数字
- 在那个“S”或“M”之后
所以每个例子:20S50M 没问题
我试过 :
awk '{ if($6 == '/[1-100][S|M][1-100][S|M]/') print} file.txt
但它没有用......我做错了什么?
这应该可以解决问题:
awk '$6~/^(([1-9]|[1-9][0-9]|100)[SM]){2}$/' file
正则说明:
^ # 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
)并且您的脚本缺少最终(合法)单引号。[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 运算符。 awk 使用如下结构condition{action}
。如果条件为 True,{}
则为正在读取的当前记录执行以下块中的操作。我的解决方案中的条件是$6~/^(([1-9]|[1-9][0-9]|100)[SM]){2}$/
可以读取第六列与正则表达式匹配的条件,如果为 True,则打印该行,因为如果您没有得到任何操作,则默认情况下awk
将执行{print $0}
。
正则表达式无法检查数值。“从 1 到 100 的数字”超出了正则表达式的功能。您可以做的是检查“1-3 位数”。
你想要这样的东西
/\d{1,3}[SM]\d{1,3}[SM]/
请注意,字符类[SM]
没有!
交替字符。仅当您将其编写为(S|M)
.
我会将正则表达式检查和数字验证作为不同的步骤进行。此代码适用于 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
编写您发布的脚本的方式:
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
发布一些示例输入和预期输出,以帮助我们为您提供更多帮助。
试试这个:
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 列中的数字保留为两位,或者在恰好 100 时保留三位 - 意味着在 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
我知道这个线程已经得到回答,但我实际上有一个类似的问题(与查找“使用查询”的字符串有关)。我正在尝试将“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 列旁边。
我希望这会有所帮助,或者至少可以帮助下一个遇到类似问题的用户。我咨询了https://stackoverflow.com/a/11339230以供参考。