私は現在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なしのデフォルト動作」です。sh
xargs
$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
sh
forループバージョンは複数回(各「単語」に対して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
使用して直接実行できます。awk
system()
パールバージョン:
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";
};
}
}