
저는 현재 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
따라서 문제는 "{}" 뒤의 모든 내용이 무시되어 두 개의 다른 파일이 동일하게 보이고 HISAT2가 작동을 멈춘다는 것입니다.
나에게 명확하지 않은 것은 "메이트"와 "싱글"의 차이점이 무엇인지, 동일한 샘플 이름을 입력하고 Unix가 해당 이름을 가진 여러 개의 다른 샘플을 지정한다는 것을 이해할 수 있도록 이 문제를 해결할 수 있는 방법이 있는지 여부입니다. 거기에?
감사합니다!
답변1
xargs 버전:
이렇게 하려면 입력 파일의 각 행을 공백으로 분할한 다음(이것이 xargs
기본 동작임) 를 xargs
사용하여 각 단어에 대해 스크립트를 한 번씩 실행해야 합니다. 또는 "$@"을 통해 쉘 스크립트 루프를 가질 수 있습니다.sh
-n 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 루프 버전은 여러 번(각 "단어"에 대해 한 번) 실행할 필요가 없으므로 더 빠릅니다 .
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";
};
}
}