Linux で複数の異なるファイルから必要な列を含む新しいファイルを作成するにはどうすればよいですか?

Linux で複数の異なるファイルから必要な列を含む新しいファイルを作成するにはどうすればよいですか?

ディレクトリ がありballgown、その中にサンプル名として約 1000 個のサブディレクトリがあります。各サブディレクトリにはファイル がありますt_data.ctab。ファイル名はすべてのサブディレクトリで同じです。

ballgown
      |_______TCGA-A2-A0T3-01A
                   |___________ t_data.ctab
      |_______TCGA-A7-A4SA-01A
                   |___________ t_data.ctab
      |_______TCGA-A7-A6VW-01A
                   |___________ t_data.ctab

上記にはballgown1000 個のサブディレクトリがあります。t_data.ctabこれら 1000 個のサブディレクトリ内のファイルは、列を含めて以下のようになります。

t_id    chr     strand  start   end     t_name  num_exons       length  gene_id gene_name       cov     FPKM
1       1       -       10060   10614   MSTRG.1.1       1       555     MSTRG.1 .       0.000000        0.000000
2       1       +       11140   30023   MSTRG.10.1      12      3981    MSTRG.10        .       2.052715        0.284182
3       1       -       11694   29342   MSTRG.11.1      8       6356    MSTRG.11        .       0.557588        0.077194
4       1       +       11869   14409   ENST00000456328.2       3       1657    MSTRG.10        DDX11L1 0.000000        0.000000
5       1       +       11937   29347   MSTRG.10.3      12      3544    MSTRG.10        .       0.000000        0.000000
6       1       -       11959   30203   MSTRG.11.2      11      4547    MSTRG.11        .       0.369929        0.051214
7       1       +       12010   13670   ENST00000450305.2       6       632     MSTRG.10        DDX11L1 0.000000        0.000000
8       1       +       12108   26994   MSTRG.10.5      10      5569    MSTRG.10        .       0.057091        0.007904
9       1       +       12804   199997  MSTRG.10.6      12      3567    MSTRG.10        .       0.000000        0.000000
10      1       +       13010   31097   MSTRG.10.7      12      4375    MSTRG.10        .       0.000000        0.000000
11      1       -       13068   26832   MSTRG.11.3      9       5457    MSTRG.11        .       0.995280        0.137788

すべてのファイルから列のみをt_data.ctab抽出して新しいファイルを作成します。新しいファイルでは、列はサンプル名である必要があります。次のようになります。t_nameFPKMFPKM

t_name         TCGA-A2-A0T3-01A TCGA-A7-A4SA-01A    TCGA-A7-A6VW-01A
MSTRG.1.1              0            0.028181                 0
MSTRG.10.1         0.284182         0.002072             0.046302
MSTRG.11.1         0.077194         0.685535             0.105849
ENST00000456328.2      0            0.307315             0.038961
MSTRG.10.3             0            0.446015             0.009946
MSTRG.11.2         0.051214         0.053577             0.036081
ENST00000450305.2      0            0.110438             0.040319
MSTRG.10.5         0.007904             0                1.430825
MSTRG.10.6             0                0                0.221105
MSTRG.10.7             0            0.199354                 0
MSTRG.11.3         0.137788         0.004792                 0

ファイルが 2 つまたは 3 つの場合は、各ファイルに -f6,12 を使用して結合できますcut。ただし、現在ファイル数は約 1000 個あります。

答え1

この簡単な方法を試してみてください:

まず最初に:

awk 'FNR==1 { print substr(FILENAME,1,16) >substr(FILENAME,1,16)".tmp" }
     FNR >1 { print $12 > substr(FILENAME,1,16)".tmp" }
     NR==FNR{ print $6  >"first_column.tmp" }' TCGA-A*/t_data.ctab

次に、pasteそれらをコンマ区切りのファイルと組み合わせます (-d,代わりにタブを使用する場合は削除します)。

paste -d, *.tmp
t_name,TCGA-A2-A0T3-01A,TCGA-A7-A4SA-01A,TCGA-A7-A6VW-01A
MSTRG.1.1,0.000000,0.00000,0.0000
MSTRG.10.1,0.284182,0.28418,0.2841
MSTRG.11.1,0.077194,0.07719,0.0771
ENST00000456328.2,0.000000,0.00000,0.0000
MSTRG.10.3,0.000000,0.00000,0.0000
MSTRG.11.2,0.051214,0.05121,0.0512
ENST00000450305.2,0.000000,0.00000,0.0000
MSTRG.10.5,0.007904,0.00790,0.0079
MSTRG.10.6,0.000000,0.00000,0.0000
MSTRG.10.7,0.000000,0.00000,0.0000
MSTRG.11.3,0.137788,0.13778,0.1377

答え2

CSV出力に満足していますか?

find ballgown -name t_data.ctab | awk ' {
  F=$0
  print F " started"
  split(F,P,"/")
  FN= P[2]
  TF[FN]=1
  getline < F
  while ((getline < F) > 0) {
    TN[$6]=1
    TV[FN ":" $6] = $NF
  }
  close(F)
  print f " done"
}
END {
  printf("tname")
  for (F in TF) {
    printf(", %s",F)
  }
  print ""
  for (N in TN) {
    printf("%s",N)
    for (F in TF) {
      printf(", %s",TV[F ":" N])
    }
    print ""
  }
}
'

答え3

質問のコメントに記載されているように、問題を 2 つの操作に分割します。これは、最初の列が各ファイルでまったく同じであり、すべてのファイルの行数が同じであるため可能です。

ボールガウン ディレクトリでの位置:

cd ballgown

最初のステップとして、最初の列を含む出力ファイルを作成します。

cut -f6 TCGA-A7-A6VW-01A/t_data.ctab > out.tab

作業の大部分は、findとの組み合わせによって行われますperl

find -iname t_data.ctab -exec perl -i.bak -lane 'if($.==1){$ARGV=~/([-\w]+)\/.*$/;$f=$1} if(1..eof&&($n=$.)){$a[$.]=$F[11];$a[1]=$f;next}; print "$_\t$a[$.-$n]"' {} out.tab \;

注記:これは破壊的なアクションです。元のファイルは.bak拡張子が追加された状態で保存されます。


非破壊バージョン、以下を使用sponge(また、ループfindに置き換えられましたfor):

for F in */t_data.ctab; do perl -lane 'if(1..eof&&($n=$.)){$a[$.]=$F[11];$a[1]=$ARGV=~s/([-\w]+)\/.*$/$1/r;next} print "$_\t$a[$.-$n]"' $F out.tab | sponge out.tab; done;

答え4

完全にプログラム化されたソリューションで、PHP の

<?php
$filenames = glob('*/t_data.ctab');
foreach($filenames as $k=>$filename) {
    $name = pathinfo($filename)['dirname'] . "\n";
    $file = file($filename);
    foreach ($file as $n => $line) {
        $line = explode("\t", $line);
        if ($n === 0) {
            $line[11] = $name;
        }
        if ($k === 0) {
            $out[$n] = $line[5] . "\t" . $line[11];
        } else {
            $out[$n] = trim($out[$n]) . "\t" . $line[11];
        }
    }
}
file_put_contents('out.tab', $out);

使用法:

  • ballgownディレクトリ内での位置づけ
  • 名前を付けてファイルを保存します。script.php
  • スクリプトを実行するphp script.php
  • 出力はout.tabファイル内にあります

注記:

PHP のインストール方法と使用方法、スクリプトの機能、特定のニーズに合わせてスクリプトを調整する方法などについてさらに説明が必要な場合はお知らせください。


同じ解決策はパイソンコメントで言語について言及されていたので、Python を書いてみました。Python を書くのは初めてなので、改善点があればぜひ提案してください。

import os, glob
out = []
for k, filename in enumerate(glob.glob('*/t_data.ctab')):
    with open(filename, 'r') as f:
        file = f.readlines()
        for n, line in enumerate(file):
            line = line.split("\t")
            if n == 0:
                line[11] = os.path.dirname(filename) + "\n"
            if k == 0:
                out.append(line[5] + "\t" + line[11])
            else:
                out[n] = out[n].strip() + "\t" + line[11]
outfile = open('out.tab', 'w')
outfile.write("".join(out))

同じアプローチで、次のように書かれていますパール一発ギャグ:

perl -lane '$a[$n].=($a[$n]?"":$F[5])."\t".($n<1?$ARGV=~s#([-\w]+)\/.*$#$1#r:$F[11]); $n=eof?0:$n+1}{print "$_" for @a' */t_data.ctab

関連情報