ファイルとシングルファイルの交配に関連する「xargs」エラー

ファイルとシングルファイルの交配に関連する「xargs」エラー

私は現在HISAT2を使用しており、複数のサンプルを入力するときにxargsを使いやすくします。

したがって、各サンプル名はスペースで区切られたテキストファイル "samples.txt"があります。

ERR199044 ERR188104 ERR188234 ERR188245 ...

私の現在のコマンドライン入力は次のとおりです。

> cat ./samples.txt| xargs -I {} sh -c "./hisat2-2.1.0/hisat2 -p 8 --dta -x ./indexes/chrX_tran -1 ./samples/{}_chrX_1.fastq.gz -2 ./samples/{}_chrX_2.fastq.gz -S ./map/{}_chrX.sam"

各入力サンプル名に使用するコマンドライン出力形式は、次のようにする必要があります。

./hisat2-2.1.0/hisat2 -p 8 --dta -x ./indexes/chrX_tran -1 ./samples/ERR199044_chrX_1.fastq.gz -2 ./samples/ERR199044_chrX_2.fastq.gz -S ./map/ERR199044_chrX.sam

次のエラーメッセージが表示されます。

Warning: Same mate file "./chrX_data/samples/ERR199044" appears as argument to both -1 and -2
Extra parameter(s) specified: "ERR188104_chrX_1.fastq.gz", "ERR188104_chrX_2.fastq.gz", "ERR188104_chrX.sam"
Note that if <mates> files are specified using -1/-2, a <singles> file cannot
also be specified.  Please run bowtie separately for mates and singles.
Error: Encountered internal HISAT2 exception (#1)
Command: /mnt/c/Alex/Lab_Files/RNAseq/tools/hisat2-2.1.0/hisat2-align-s --wrapper basic-0 -p 8 --dta -x ./chrX_data/indexes/chrX_tran -S ./map/ERR199044 -1 ./chrX_data/samples/ERR199044 -2 ./chrX_data/samples/ERR199044 ERR188104_chrX_1.fastq.gz ERR188104_chrX_2.fastq.gz ERR188104_chrX.sam
(ERR): hisat2-align exited with value 1

したがって、問題は、「{}」の後ろのすべての内容が無視され、2つの異なるファイルが同じに見え、HISAT2が動作を停止することです。

私にとって明確ではないのは、「合致」と「シングル」の違いが何であるか、同じサンプル名を入力し、Unixがその名前を持つ複数の異なるサンプルを指定することを理解できるように、この問題を解決する方法です。あるかどうか。そこに?

ありがとうございます!

ベストアンサー1

xargs バージョン:

これを行うには、入力ファイルの各行をスペースに分割し(これがデフォルトの動作です)、各xargs単語xargsに対してスクリプトを1回実行する必要があります。あるいは、「$@」を介してシェルスクリプトループを持つこともできます。sh-n 1

入力ファイルは一度に1行ずつ読み取られるため、-I {}ここでは使用できません。xargs区切り文字を空白に設定しても、-d ' '次の入力行を読み始めると、各入力行の終わりにエラーが発生します。

幸いなことに、これをまったく使用する必要はありません。すでに-I {}入力のエコーワードをコマンドラインの末尾に別の引数として追加していますが、これは「-Iなしのデフォルト動作」です。shxargs

$1シェルスクリプトは、他のシェルスクリプトと同様に、位置パラメータ(つまり)を介してパラメータを参照します。$1シェルスクリプトで自由に使用できます。

psまた、コマンドに引数0を指定する必要があります(shプロセスの任意の名前 - "sh"文字列も便利です。ただし、sh -c '...script...'これはパラメータの後の最初のパラメータでなければならず、シェルスクリプト内に'...script...'あります)。$0

したがって、次のように実行する必要があります(forループなし)。

xargs -n 1 sh -c \
  './hisat2-2.1.0/hisat2 -p 8 --dta -x ./indexes/chrX_tran \
    -1 "./samples/$1_chrX_1.fastq.gz" -2 "./samples/$1_chrX_2.fastq.gz" \
    -S "./map/$1_chrX.sam"' sh < ./samples.txt

または(forループを使用):

xargs sh -c '
  for f in "$@"; do \
    ./hisat2-2.1.0/hisat2 -p 8 --dta -x ./indexes/chrX_tran \
      -1 "./samples/${f}_chrX_1.fastq.gz" -2 "./samples/${f}_chrX_2.fastq.gz" \
      -S "./map/${f}_chrX.sam"
  done' sh < ./samples.txt

shforループバージョンは複数回(各「単語」に対して1回)実行する必要がないため、より高速です。

shシェルの最大コマンドライン長(最新システムでは約2MB)によって制限され、できるだけ少ない回数で実行されます。非常に大きい場合(200,000以上の項目)でなければ、一度だけsamples.txt実行されるという意味ですsh

シェルを読みながらループ:

このような操作にはxargsは必要ありません。以下はbashで動作し、おそらく-a配列とread

while read -a words; do
  for f in "${words[@]}"; do 
    ./hisat2-2.1.0/hisat2 -p 8 --dta -x ./indexes/chrX_tran \
      -1 "./samples/${f}_chrX_1.fastq.gz" \
      -2 "./samples/${f}_chrX_2.fastq.gz" \
      -S "./map/${f}_chrX.sam"
  done
done < samples.txt

これは、各入力行の各単語をbash配列として読み取り、(配列内のfor各単語のループを使用して)適切なパラメータを使用してhisat2プログラムを実行します。

ただし、以下を参照してください。シェルループを使用してテキストを処理するのはなぜ悪い習慣と見なされますか?

awkバージョン:

awk '{
  for (i=1;i<=NF;i++) {
    printf "./hisat2-2.1.0/hisat2 -p 8 --dta -x ./indexes/chrX_tran -1 \"./samples/%s_chrX_1.fastq.gz\" -2 \"./samples/%s_chrX_2.fastq.gz\" -S \"./map/%s_chrX.sam\"\n", $i, $i,$i;
  }
}' ./samples.txt | sh

これは実行のためにawkの出力をshにパイプすることに注意してください。 sh に対応するパイプがない場合、出力は次のようになります。

./hisat2-2.1.0/hisat2 -p 8 --dta -x ./indexes/chrX_tran -1 "./samples/ERR199044_chrX_1.fastq.gz" -2 "./samples/ERR199044_chrX_2.fastq.gz" -S "./map/ERR199044_chrX.sam"
./hisat2-2.1.0/hisat2 -p 8 --dta -x ./indexes/chrX_tran -1 "./samples/ERR188104_chrX_1.fastq.gz" -2 "./samples/ERR188104_chrX_2.fastq.gz" -S "./map/ERR188104_chrX.sam"
./hisat2-2.1.0/hisat2 -p 8 --dta -x ./indexes/chrX_tran -1 "./samples/ERR188234_chrX_1.fastq.gz" -2 "./samples/ERR188234_chrX_2.fastq.gz" -S "./map/ERR188234_chrX.sam"
./hisat2-2.1.0/hisat2 -p 8 --dta -x ./indexes/chrX_tran -1 "./samples/ERR188245_chrX_1.fastq.gz" -2 "./samples/ERR188245_chrX_2.fastq.gz" -S "./map/ERR188245_chrX.sam"

また、shスクリプトは、各行を印刷するときにawkスクリプトを実行するため、すばやく実行されます。

あるいは、標準出力の代わりにsprintfコマンドラインを変数に入れることもできます。その後、次のPerlの例と同様に、s関数をprintf使用して直接実行できます。awksystem()

パールバージョン:

perl -lane '
  foreach $f (@F) {
    system(qw(./hisat2-2.1.0/hisat2 -p 8 --dta -x ./indexes/chrX_tran),
      -1, "./samples/${f}_chrX_1.fastq.gz",
      -2, "./samples/${f}_chrX_2.fastq.gz",
      "-S", "./map/${f}_chrX.sam");
  };' ./samples.txt

perl関数を使用するsystem()ので、コマンドをsh

テスト実行の場合は、引用演算子のecho直後に単語とスペースを追加します。qw(

ちなみに、このPerlバージョンにコードを追加してファイルが存在するかどうかを確認したり、各実行の成功をテストしたり、シェルやawkバージョンよりも出力を後処理したりする方が簡単です。./hisat2-2.1.0/hisat2特にスタンドアロンのAスクリプトで書かれている場合はさらにそうです。ラインよりも。たとえば、

#!/usr/bin/perl -w

use strict;

while(<>) {
  foreach my $f (split) {
    my $f1 = "./samples/${f}_chrX_1.fastq.gz";
    my $f2 = "./samples/${f}_chrX_2.fastq.gz";
    my $sam = "./map/${f}_chrX.sam";

    if (!(-r $f1 && -r $f2 && -r $sam)) {
      warn "Missing or unreadable file for $f\n";
      next
    };

    my $rc = system(
        qw(echo ./hisat2-2.1.0/hisat2 -p 8 --dta -x ./indexes/chrX_tran),
        -1, $f1, -2, $f2, '-S', $sam
    );

    if ($rc) {
      warn "hisat2 returned non-zero exit code for $f: $rc\n";
    };
  }
}

おすすめ記事