ファイルから値をgrepし、FILENAMEに基づいて別のファイルに印刷する方法

ファイルから値をgrepし、FILENAMEに基づいて別のファイルに印刷する方法

A_bla.csv(例:など...)などの複数のファイルがありますB_bla.csv C_bla.csv(これは実際のファイルのソートサブサンプルですが、開くことは実際です)。

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.csvcoverage各ファイルの4列、89行のフィールドをファイル列に印刷したいと思います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

魔法は何ですか?e代替コマンドのxecuteオプションを使用し、別のコマンドを使用してs89行目の4番目のフィールドを抽出します。sed詳細:

  • 1n最初の行は変更せずに残します。
  • h混乱する前に予約済みのスペースに行を保存してください
  • \([[:alnum:]]\).*行全体を一致させ、交換時に\(\)参照できるように、最初の英数字フィールドをキャプチャします。\1
  • sed -E "89!d;s_([^,]*,){3}__;s_,.*__" \1_bla.csv代替方法は次のとおりです。 89以外のすべての行が削除され、最初の3つのdフィールドが削除され、最後に新しい最初のフィールド以降のすべての項目が削除されます。したがって、実際には89行の4番目のフィールドだけが残っているため、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ファイルの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

関連情報