如何 grep 文件中的值并根据 FILENAME 将其打印到另一个文件中

如何 grep 文件中的值并根据 FILENAME 将其打印到另一个文件中

我有几个文件,例如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

相关内容