我有几个文件,例如A_bla.csv
(即B_bla.csv
C_bla.csv
等...)(这是真实文件的 lign 子采样,但列数是真实的):
1,test,test2,55.2,test3
1,test,test2,96.3,test3
1,test,test2,64.2,test3
1,test,test2,97.2,test3
和一个主文件main.tsv
(字段分隔符 = \t
):
id coverage clade
A wrongdata 20
B wrongdata 19
C wrongdata 19
*_bla.csv
我想将每个文件中第 4 列第 89 行的字段打印到文件coverage
列中main.tsv
。为此,我需要使用*_bla.csv
文件的 FILENAME 并将其用作文件id
列的模式main.tsv
。
到目前为止我尝试过:
for file in *_bla.csv ; do
r="$(basename -s "_bla.csv" $file)"
awk ... ;
done
但我即将开始回答。您知道如何仅使用 Linux 机器中默认的工具(awk、grep、sed、python、perl ...)来做到这一点吗?谢谢
答案1
不可避免的 GNUsed
一句台词:
sed '1n;h;s/\([[:alnum:]]\).*/sed -E "89!d;s_([^,]*,){3}__;s_,.*__" \1_bla.csv/e;G;s/\(.*\)\n\(.*\)wrongdata/\2\1/' main.tsv
有什么魔力?我们使用ubstitute 命令e
的 xecute 选项,用另一个命令s
提取第 89 行的第 4 个字段。sed
详细地:
1n
保持第一行不变h
在我们搞砸之前将线存储在保留空间中\([[:alnum:]]\).*
匹配整行并捕获第一个字母数字字段,以便我们可以在替换中\(\)
引用它\1
sed -E "89!d;s_([^,]*,){3}__;s_,.*__" \1_bla.csv
是这样的替换:除 89 之外的所有行都将被d
删除,然后前三个字段将被删除,最后新的第一个字段之后的所有内容都会被删除。所以实际上只有第 89 行的第四个字段幸存下来,所以这将由e
缓冲区的执行返回- 现在我们只需要将保存空间中的保存行附加到
G
并用提取的字段s/\(.*\)\n\(.*\)wrongdata/\2\1/
替换即可。wrongdata
答案2
awk -F',|\t' '
FILENAME != "main.tsv" && FNR == 89 {
sub(/_.*$/, "", FILENAME)
A[FILENAME]=$4
}
FILENAME != "main.tsv" {next}
A[$1] {$2 = A[$1]}
{print}
' *bla.csv OFS='\t' main.tsv
我看到文件中没有制表符分隔符main.tsv
。然后需要像这样纠正模式:-F',|[[:blank:]]+'
答案3
您可以使用 awk 实用程序来完成。必须从 csv 文件所在的目录运行。
awk -v OFS='\t' '
FS=="," && FNR==89 {
split(FILENAME, a, "_")
h[substr(a[1],3)] = $4
}
f=FS=="\t" {
$2 = FNR>1&&($1 in h) ? h[$1] : $2
};f
' FS=, ./*_bla.csv FS="\t" ./main.tsv
id coverage clade
A 35.8 20
B 65.7 19
C 35.8 19
perl -F, -lane '
if (@ARGV) {
89..89 && do{
$h{($ARGV=~/^..(\w+)_/)[0]} = $F[3];
close ARGV;
};
} else { #last file here
@F = split "(\t)";
$F[2] = $h{$F[0]} // $F[2];
print($.>1?@F:$_)
}
' ./*_bla.csv ./main.tsv
GNU sed。但首先我们从每个 CSV 文件中 grep 出第 89 行、第 4 个字段,对出现的数据进行转义,以便安全地插入 sed s/// 语句的 RHS。
hold=$(
grep -Pzo '^(?:.*\n){88}(?:[^,]*,){3}\K[^,]*' -- *_bla.csv |
tr '\0' '\n'|
sed -Ee '
s/_.*:/\t/
s:[\&/]:\\&:g
$!s:$:\\:
')
sed -En \
-e "1{x;s/.*/$hold/;x;}" \
-e '
1!G
s/^(\S+\t)wrongdata(\t.*)\n\1([^\n]*)/\1\3\2/
P
' \
./main.tsv
python3 -c '
import sys, pathlib, itertools
mainf = sys.argv[1]
fs,rs = ofs,ors = "\t","\n"
d,dlm = {},","
for p in pathlib.Path(".").glob("*_bla.csv"):
if p.is_file():
id = p.name[:p.name.find("_")]
with open(p.name) as f:
d[id] = [l.rstrip(rs).split(dlm)[3] for l in itertools.islice(f,88,89)][0]
with open(mainf) as f:
for l in f:
L = l.rstrip(rs).split(fs)
print(L[0], d.get(L[0],L[1]), *L[2:], sep=ofs)
' ./main.tsv