我需要加快一个脚本的速度,该脚本本质上确定每行的所有“列”是否相同,然后写入一个包含相同元素之一或“no_match”的新文件。该文件以逗号分隔,由大约 15,000 行组成,并包含不同数量的“列”。
例如:
1-69
4-59,4-59,4-59,4-61,4-61,4-61
1-46,1-46
4-59,4-59,4-59,4-61,4-61,4-61
6-1,6-1
5-51,5-51
4-59,4-59
写入一个新文件:
1-69
no_match
1-46
no_match
6-1
5-51
4-59
删除第二行和第四行,因为它们包含不相同的列。
这是我远非优雅的脚本:
#!/bin/bash
ind=$1 #file in
num=`wc -l "$ind"|cut -d' ' -f1` #number of lines in 'file in'
echo "alleles" > same_alleles.txt #new file to write to
#loop over every line of 'file in'
for (( i =2; i <= "$num"; i++));do
#take first column of row being looped over (string to check match of other columns with)
match=`awk "FNR=="$i" {print}" "$ind"|cut -d, -f1`
#counts how many matches there are in the looped row
match_num=`awk "FNR=="$i" {print}" "$ind"|grep -o "$match"|wc -l|cut -d' ' -f1`
#counts number of commas in each looped row
comma_num=`awk "FNR=="$i" {print}" "$ind"|grep -o ","|wc -l|cut -d' ' -f1`
#number of columns in each row
tot_num=$((comma_num + 1))
#writes one of the identical elements if all contents of row are identical, or writes "no_match" otherwise
if [ "$tot_num" == "$match_num" ]; then
echo $match >> same_alleles.txt
else
echo "no_match" >> same_alleles.txt
fi
done
#END
目前,该脚本大约需要 11 分钟才能完成全部约 15,000 行。我不太确定如何加快速度(老实说我很惊讶我什至可以让它工作)。任何时间被取消都会很棒。下面是可以使用的 100 行的较小摘录:
allele
4-39
1-46,1-46,1-46
4-39
4-4,4-4,4-4,4-4
3-23,3-23,3-23
3-21,3-21
4-34,4-34
3-33
4-4,4-4,4-4
4-59,4-59
3-23,3-23,3-23
1-45
1-46,1-46
3-23,3-23,3-23
4-61
1-8
3-7
4-4
4-59,4-59,4-59
1-18,1-18
3-21,3-21
3-23,3-23,3-23
3-23,3-23,3-23
3-30,3-30-3
4-39,4-39
4-61
2-70
4-38-2,4-38-2
1-69,1-69,1-69,1-69,1-69
1-69
4-59,4-59,4-59,4-61,4-61,4-61
1-46,1-46
4-59,4-59,4-59,4-61,4-61,4-61
6-1,6-1
5-51,5-51
4-59,4-59
1-18
3-7
1-69
4-30-4
4-39
1-69
1-69
4-39
3-23,3-23,3-23
4-39
2-5
3-30-3
4-59,4-59,4-59
3-21,3-21
4-59,4-59
3-9
4-59,4-59,4-59
4-31,4-31
1-46,1-46
1-46,1-46,1-46
5-51,5-51
3-48
4-31,4-31
3-7
4-61
4-59,4-59,4-59,4-61,4-61,4-61
4-38-2,4-38-2
3-21,3-21
1-69,1-69,1-69
3-23,3-23,3-23
4-59,4-59
3-48
3-48
1-46,1-46
3-23,3-23,3-23
3-30-3,3-30-3
1-46,1-46,1-46
3-64
3-73,3-73
4-4
1-18
3-7
1-46,1-46
1-3
4-61
2-70
4-59,4-59
5-51,5-51
3-49,3-49
4-4,4-4,4-4
4-31,4-31
1-69
1-69,1-69,1-69
4-39
3-21,3-21
3-33
3-9
3-48
4-59,4-59
4-59,4-59
4-39,4-39
3-21,3-21
1-18
我的脚本大约需要 7 秒才能完成此操作。
答案1
$ awk -F, '{ for (i=2; i<=NF; ++i) if ($i != $1) { print "no_match"; next } print $1 }' file
1-69
no_match
1-46
no_match
6-1
5-51
4-59
抱歉,我什至没有看你的代码,发生了太多事情。当您发现自己awk
在循环体中对相同数据调用了三次时,您将不得不寻找其他方法来更有效地完成它。另外,如果您涉及awk
,您不需要grep
并且cut
可以awk
轻松完成他们的任务(尽管在本例中不需要)。
上面的脚本awk
一次读取一行以逗号分隔的行,并将每个字段与第一个字段进行比较。如果任何测试失败,no_match
则会打印该字符串,并且脚本继续执行下一行。如果循环完成(没有发现不匹配),则打印第一个字段。
作为脚本:
#!/usr/bin/awk -f
BEGIN { FS = "," }
{
for (i=2; i<=NF; ++i)
if ($i != $1) {
print "no_match"
next
}
print $1
}
FS
是输入字段分隔符,也可以使用-F
命令行上的选项进行设置。awk
将分割该字符上的每一行以创建字段。NF
是当前记录中的字段数(“行上的列数”)。$i
指当前记录中的第 i:th 字段,其中i
可以是变量或常量(如 中$1
)。
有关的:
干燥变化:
#!/usr/bin/awk -f
BEGIN { FS = "," }
{
output = $1
for (i=2; i<=NF; ++i)
if ($i != output) {
output = "no_match"
break
}
print output
}
答案2
Awk 是一种完整的编程语言。你已经使用它了。但不要仅将其用于每行多次调用的简单任务,而应将其用于整个任务。 awk 中使用字段分隔符,不要使用 cut。在 awk 中进行完整的处理。
awk -F',' '
{
eq=1;
for (i = 2; i <= NF; i++)
if ($1 != $i)
eq=0;
print eq ? $1 : "no_match";
}
' $1
答案3
使用 perl List::MoreUtils
,通过评估标量上下文中的distinct
/元素:uniq
perl -MList::MoreUtils=distinct -F, -lne '
print( (distinct @F) > 1 ? "no_match" : $F[0])
' example
1-69
no_match
1-46
no_match
6-1
5-51
4-59
答案4
您也可以使用编辑器执行此操作sed
,如下所示:
sed -e '
s/^\([^,]*\)\(,\1\)*$/\1/;t
s/.*/NOMATCH/
' input.csv
在这里,我们依靠 进行regex
自我乘法并到达行尾。如果能够这样做,则以第一个字段终止,否则 flash NOMATCH
。
解释:
当我看到这个 pbm 时,我的脑海中浮现出这样的想法:
想想不同颜色的comma-separated fields
as 。stones
想象它们是否可以排成一行,作为第一块石头的重复,并在它们前面加上逗号。
就像是:
STONEA ,STONEA ,STONEA ,STONEA ... all the way to end of line
现在,就正则表达式术语而言,它变成:
^ (STONEA) (,\1) (,\1) (,\1) ... all the way to end of line
^ (STONEA) (,\1)* $
输出:
1-69
NOMATCH
1-46
NOMATCH
6-1
5-51
4-59