我有 3 个文件,以空格分隔,大约有 340 万行(但它们的行数并不完全相同,并且按“标记”列排序)。它们看起来像这样:
head neu1
Chr BP Marker MAF A1 A2 Direction pValue N 1 100000012 1:100000012:G:T 0.229925 T G + 0.650403 1594 1 100000827 1:100000827:C:T 0.287014 T C + 0.955449 1594 1 100002713 1:100002713:C:T 0.097867 T C - 0.290455 1594 1 100002882 1:100002882:T:G 0.287014 G T + 0.955449 1594 1 100002991 1:100002991:G:A 0.097867 A G - 0.290455 1594 1 100004726 1:100004725:G:A 0.132058 A G + 0.115005 1594
head nep1
Chr BP Marker MAF A1 A2 Direction pValue N 1 100000012 1:100000012:G:T 0.2300430 T G - 0.1420030 1641 1 100000827 1:100000827:C:T 0.2867150 T C - 0.2045580 1641 1 100002713 1:100002713:C:T 0.0975015 T C - 0.0555507 1641 1 100002882 1:100002882:T:G 0.2867150 G T - 0.2045580 1641 1 100002991 1:100002994:G:A 0.0975015 A G - 0.0555507 1641 1 100004726 1:100004726:G:A 0.1325410 A G - 0.8725660 1641
head ret1
Chr BP Marker MAF A1 A2 Direction pValue N 1 100000012 1:100000012:G:T 0.2322760 T G - 0.230383 1608 1 100000827 1:100000827:C:T 0.2882460 T C - 0.120356 1608 1 100002713 1:100002713:C:T 0.0982587 T C - 0.272936 1608 1 100002882 1:100002883:T:G 0.2882460 G T - 0.120356 1608 1 100002991 1:100002991:G:A 0.0982587 A G - 0.272936 1608 1 100004726 1:100004726:G:A 0.1340170 A G - 0.594538 1608
有没有办法创建另外 3 个文件,例如neu2
, nep2
,ret2
其中仅包含“标记”列(第三列)中的值对于所有 3 个原始文件都相同的行?
我应该提到,输出文件应包含初始文件中的所有 9 列。
预期输出将是这 3 个文件:
head neu2
Chr BP Marker MAF A1 A2 Direction pValue N 1 100000012 1:100000012:G:T 0.229925 T G + 0.650403 1594 1 100000827 1:100000827:C:T 0.287014 T C + 0.955449 1594 1 100002713 1:100002713:C:T 0.097867 T C - 0.290455 1594
head nep1
Chr BP Marker MAF A1 A2 Direction pValue N 1 100000012 1:100000012:G:T 0.2300430 T G - 0.1420030 1641 1 100000827 1:100000827:C:T 0.2867150 T C - 0.2045580 1641 1 100002713 1:100002713:C:T 0.0975015 T C - 0.0555507 1641
head ret1
Chr BP Marker MAF A1 A2 Direction pValue N 1 100000012 1:100000012:G:T 0.2322760 T G - 0.230383 1608 1 100000827 1:100000827:C:T 0.2882460 T C - 0.120356 1608 1 100002713 1:100002713:C:T 0.0982587 T C - 0.272936 1608
3 个文件中每一个的标头都存在于初始文件和结果文件中,分别是 9 个:
Chr BP Marker MAF A1 A2 Direction pValue N
答案1
这应该既快速又高效。它使用join
(部分GNU 核心工具) 和field
( 的一部分探戈工具):
# This finds the matching lines and makes it into a big file with 25 columns
join -1 3 -2 3 neu1 nep1 | join -1 1 -2 3 - ret1 |
# Now split the right columns
# field is https://gitlab.com/ole.tange/tangetools/-/tree/master/field
tee > >(field 2-3,1,4-9 > neu2) >(field 10-11,1,12-17 > nep2) >(field 18-19,1,20-25 > ret2)
答案2
$ cat ../tst.awk
ARGIND < 4 {
if ( FNR == 1 ) {
ARGV[ARGC] = FILENAME
ARGC++
}
if ( !seen[ARGIND,$3]++ ) {
cnt[$3]++
}
next
}
FNR == 1 {
close(out)
out = FILENAME
sub(/1/,"2",out)
}
cnt[$3] == 3 {
print $0 " > " out
}
。
$ awk -f ../tst.awk neu1 nep1 ret1
Chr BP Marker MAF A1 A2 Direction pValue N > neu2
1 100000012 1:100000012:G:T 0.229925 T G + 0.650403 1594 > neu2
1 100000827 1:100000827:C:T 0.287014 T C + 0.955449 1594 > neu2
1 100002713 1:100002713:C:T 0.097867 T C - 0.290455 1594 > neu2
Chr BP Marker MAF A1 A2 Direction pValue N > nep2
1 100000012 1:100000012:G:T 0.2300430 T G - 0.1420030 1641 > nep2
1 100000827 1:100000827:C:T 0.2867150 T C - 0.2045580 1641 > nep2
1 100002713 1:100002713:C:T 0.0975015 T C - 0.0555507 1641 > nep2
Chr BP Marker MAF A1 A2 Direction pValue N > ret2
1 100000012 1:100000012:G:T 0.2322760 T G - 0.230383 1608 > ret2
1 100000827 1:100000827:C:T 0.2882460 T C - 0.120356 1608 > ret2
1 100002713 1:100002713:C:T 0.0982587 T C - 0.272936 1608 > ret2
更改print $0 " > " out
为print > out
完成测试后实际生成所需的输出文件。上面使用 GNU awk for ARGIND
,如果您没有 GNU awk,则只需添加FNR==1 { ARGIND++ }
为脚本的第一行。
答案3
这确实是一个很好的问题。如果您确定文件按第三列升序排序,我建议使用与“SQL 世界”中的合并连接类似的方法。文件的排序必须使用相同的排序函数来完成,该函数用于比较 bash 中的字符串。下面的脚本需要 bash。应该通过以下方式调用它:
$ script file1 file2 file3
它将创建 3 个输出文件:file1.out file2.out file3.out。它们包含来自各自源文件的行,这些行在第三列中具有值,该列存在于所有输入文件中。具有此类值的所有行都位于“.out”文件中。
#!/bin/bash
Fil1="$1"
Fil2="$2"
Fil3="$3"
# Opening file descriptors for reading
exec 10<"$Fil1"
exec 20<"$Fil2"
exec 30<"$Fil3"
# Open output files
exec 11>"$Fil1".out
exec 21>"$Fil2".out
exec 31>"$Fil3".out
# First line is copied without changes.
IFS= read -r -u 10 Line1
printf "%s\n" "$Line1" >&11
IFS= read -r -u 20 Line2
printf "%s\n" "$Line2" >&21
IFS= read -r -u 30 Line3
printf "%s\n" "$Line3" >&31
# Prepare to walk through files, searching for identical values in the third column.
IFS= read -r -u 10 Line1
if [ $? -eq 0 ] ; then RC1=0; else RC1=1; fi
read -r F11 F12 F13 F1 <<< "$Line1"
IFS= read -r -u 20 Line2
if [ $? -eq 0 ] ; then RC2=0; else RC2=1; fi
read -r F21 F22 F23 F2 <<< "$Line2"
IFS= read -r -u 30 Line3
if [ $? -eq 0 ] ; then RC3=0; else RC3=1; fi
read -r F31 F32 F33 F3 <<< "$Line3"
while [ $RC1 -eq 0 ] && [ $RC2 -eq 0 ] && [ $RC3 -eq 0 ]
do
while [ "$F23" \< "$F13" ]
do
IFS= read -r -u 20 Line2
if [ $? -eq 0 ] ; then RC2=0; else RC2=1; break; fi
read -r F21 F22 F23 F2 <<< "$Line2"
done
if [ $RC2 -ne 0 ]; then break; fi
if [ "$F23" = "$F13" ]
then
FFF="$F23"
while [ "$F33" \< "$FFF" ]
do
IFS= read -r -u 30 Line3
if [ $? -eq 0 ] ; then RC3=0; else RC3=1; break; fi
read -r F31 F32 F33 F3 <<< "$Line3"
done
if [ $RC3 -ne 0 ]; then break; fi
if [ "$F33" = "$FFF" ]
then
while [ "$F23" = "$FFF" ]
do
printf "%s\n" "$Line2" >&21
IFS= read -r -u 20 Line2
if [ $? -eq 0 ] ; then RC2=0; else RC2=1; break; fi
read -r F21 F22 F23 F2 <<< "$Line2"
done
while [ "$F13" = "$FFF" ]
do
printf "%s\n" "$Line1" >&11
IFS= read -r -u 10 Line1
if [ $? -eq 0 ] ; then RC1=0; else RC1=1; break; fi
read -r F11 F12 F13 F1 <<< "$Line1"
done
while [ "$F33" = "$FFF" ]
do
printf "%s\n" "$Line3" >&31
IFS= read -r -u 30 Line3
if [ $? -eq 0 ] ; then RC3=0; else RC3=1; break; fi
read -r F31 F32 F33 F3 <<< "$Line3"
done
if [ $RC1 -ne 0 ] || [ $RC2 -ne 0 ] || [ $RC3 -ne 0 ]; then break; fi
fi
fi
while [ "$F33" \> "$F23" ]
do
IFS= read -r -u 20 Line2
if [ $? -eq 0 ] ; then RC2=0; else RC2=1; break; fi
read -r F21 F22 F23 F2 <<< "$Line2"
done
while [ "$F23" \> "$F13" ]
do
IFS= read -r -u 10 Line1
if [ $? -eq 0 ] ; then RC1=0; else RC1=1; break; fi
read -r F11 F12 F13 F1 <<< "$Line1"
done
done
# close files
exec 10>&-
exec 11>&-
exec 20>&-
exec 21>&-
该脚本仅读取文件一次,并交替前进。因此,所有输入文件必须同时打开。这在 bash 中是可能的,但 shell 并不是进行此类处理的好工具。对于大型输入文件,通过用 C 语言编写,您可能会获得更好的结果。也可以更轻松地为代码提供更好的结构,并完全控制过程。